Saturday, August 31, 2013

AngularJS Lightbox directive

I was using lightbox2 in an AngularJS app and realized that it was pretty difficult to customize it.
The requirements were very simple,
  1. editing the album name/ picture description
  2. deleting album/picture 
  3. different overlay than the usual title below/above the image
Although the last one I would have found support in some library or the other if I searched but the first two needed to have callbacks to my AngularJS app. This prompted me to write a directive which could be easily configured/customized.

I made use of AngularUI modal since that was already used in my app. Besides, as they say, no point in rewriting stuff that's already there.

The usage is pretty simple,
<lightbox images="album"></lightbox>

where album is an array of image details. A sample image detail object would be
{src: "/path/to/img", header: "the data/info that should be displayed above the image", description: "the info to be displayed beside the image"}

The header and the description can also be HTML strings. The dimensions in tile view are 150px x 150px by default. 

The directive can be customized/configured to handle various cases (inline editing using contenteditable, delete, change tile size, background, etc)


Friday, March 1, 2013

How MapReduce works

Inspired by the map and reduce operations in functional languages, Google came up with a programming model and implementation to handle operations on huge data in a time-efficient manner.

In order to use MapReduce, the user needs to define two functions:
the Map function, which generates an intermediate map 
and the Reduce function, which operates on the intermediate map resulting in desired output.

When the user program calls the MapReduce function,

  1. The MapReduce library in the user program splits the input files into M pieces and copies of the program are started on a cluster of machines. One of these copies is master and is responsible for assigning the M map tasks and the R reduce tasks to the workers(others).
  2. When a map task is completed, the intermediate key/value pairs are buffered in memory. These buffered pairs are periodically written to local disk which is partitioned into R regions by the partitioning function. The master is responsible for forwarding these locations to the reducer workers. 
  3. When the master notifies a reduce worker about the locations, it uses remote procedure calls to read the buffered data from the local disks of the map workers. 
  4. After reading all the intermediate data, the reduce worker sorts the data by the intermediate keys. This ensures that all occurrences of a key are grouped together.
  5. Then, the reduce worker iterates over the sorted data and for each unique key encountered, it passes the key and the corresponding set of intermediate values to the user's Reduce function. 
  6. The output from the Reduce function is appended to a final output file for that reduce partition.

Once all the map and reduce tasks are completed, the MapReduce call in the user program returns back to the user code and the output of the MapReduce execution is available in the R output files.

Thursday, February 28, 2013

Converting Play 2.1 JSON to Scala XML

Working with JSON and XML is pretty simple in Play-framework. For JSON, it is recommended to use Play's type-class based library.

I recently, came across a scenario where I had to convert Play 2.1 JSON to Scala XML and vice versa. I didn't find any internal classes in Play which could handle this. Lift provides a tool to handle a similar conversion.

To convert the JSON into XML I used recursion. Although, the scala.xml.Elem constructor allows only one Node to be added as child, there is another method copy, which takes in a Seq[Node] as child.  

To handle conversion from XML to JSON, I modified the toJson method in Lift to result in Play JSON. 

Link to gist



Friday, January 11, 2013

File Upload using AngularJs

Although AngularJs does not support file upload, as of now, there are several ways to achieve it using the input tag.

One method is to integrate file upload plugins. An alternative to that is sending form-data.

Sending form data is simple,

$http.post('/path/of/request', fd, {
     headers: { 'Content-Type': undefined},
     transformRequest: angular.identity
   }).success(function (result) {
     alert(result);
   });

where fd is a FormData Object.

The file can be set using the files property of the input element.

We could also use XMLHTTPRequest to upload a file. Link to a simple component to upload a file

In this directive, component is an angular module and it can simply be used by having a 'fileUpload' tag.

Note: This doesn't work in older versions of IE where there is no FormData object. Those interested can check stackoverflow or filepicker.

Sunday, December 30, 2012

Handling a form with an image and multiple other fields in Play (Scala)

File upload along with other data is a common scenario. This can be handled in Play framework in different ways. 

One case is where Play Forms are used. (refer Play Documentation)
Another case is using custom forms and Play Framework as backend.  (An example function definition)

The file can be accessed using 

request.body.file("fileName")

and in the second case, the fields can be accessed using 

(request.body).asFormUrlEncoded.get("fieldName").get(0)

asFormUrlEncoded returns a Map[ String, Seq [ String ] ] Object. Thus, in order to get the value of a parameter we need to use get(0). 


Note: while using Play Form, it is better to complete the data transactions and handle file upload in its success call

signupForm.bindFromRequest.fold(
  formWithErrors => BadRequest(html.register(formWithErrors)),
  user => {
    request.body.file("picture").map {
      picture =>
        val fileName = user._1
        val path="/path/to/destination/"
        ...

Wednesday, December 12, 2012

Testing AngularJS app in IntelliJ


Install jsTestDriver plugin for IntelliJ

Ensure that the following files exist within your project

  1. jquery-1.8.3.js
  2. jasmine-1.1.0.js *
  3. JasmineAdapter-1.1.2.js *
  4. angular-resource.js
  5. angular-mocks.js

Create a .jstd file in your project folder.(eg ‘TestConfig.jstd’).The file should be something like this
           
Create a test file. Write your test cases using Jasmine and run them using JsTestDriver plugin. 

Note: if u add angular-mocks.js before jasmine, on running the tests, you may get a reference error - module/inject not defined


* while writing the test cases, IntelliJ prompts to add JasmineAdapter and jasmine you could add them then as well

Thursday, November 8, 2012

Setting up Play-Scala Project in IntelliJ Idea


The easiest way to setup a Play-Scala project is by using the giter8 template.

Setup the project using by giving the following command in the terminal

$ g8 typesafehub/play-scala
# cd into the newly created directory and run with 'sbt run'

In the sbt console
$ idea

Once this is done, the project can be opened from Idea.

Setting up database for the project
  1. Add the database driver in project/Build.scala (throws driver not found error on being skipped)
  2. In conf/application.conf specify the database configuration(more on database in play)
  3. In conf/evolutions/default create a file 1.sql which has the database schema(more on evolutions)

Prerequisites
  1. sbt
  2. giter8
  3. Play and Scala plugin for IntelliJ Idea