Monday, September 8, 2014

Kendo UI's ListView for AngularJS doesn't work

File this under "what a waste of time".

So I was trying to get Kendo UI's ListView to work with AngularJS. But it doesn't render. So I assume its my fault and tried for hours to get it to work. Stepping through Javascript (not the most pleasant of tasks), searching Stackoverflow (not the most pleasant of tasks).

Guess what was the problem?

In the Kendo UI AngularJS example above, the Kendo UI directive was kendo-listview. That doesn't work with my version of Kendo UI.

It should be kendo-list-view.

Wow, what a waste of my time.

Friday, September 5, 2014

How to upload file data using Spring MVC, Angular JS and Kendo UI

Uploading a file in Spring is one of those super important things to know about, which, for some reason, none of my past projects required me to do. And suddenly I have to asynchronously upload a file using Kendo UI, AngularJS and Spring MVC. The widget I use in Kendo UI is "Upload" Here are the steps we need to do.


  1. Enable Spring’s built-in multipart handling.
  2. Create a method in the Spring controller that will handle the multipart POST.
  3. Create the Kendo UI Upload widget.



1. Enable Spring’s built-in multipart handling
By default, Spring does no multipart handling. This is done by adding a "multipart resolver" bean. I chose to use a multipart resolver that uses Apache Commons FileUpload package (which is mature and robust). First include the package. I use Maven. So do it like this:
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.2.1</version>
</dependency>

Then I add the multipart resolver into the Spring configuration:
    <bean id="multipartResolver"
          class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />
(the id attribute was not needed in my case)



2. Create a method in the Spring controller that will handle the multipart POST.
This method will only accept POST calls. It will have a MultiPart parameter, which contains (or contains information about) the file data. All the temporary file data will be cleared at the end of request processing.
@RequestMapping(value = "uploadFile", method = RequestMethod.POST)
@ResponseBody
public Map<String, String> uploadImage( @RequestParam("file") MultipartFile file, 
                                                     @RequestParam("username") String userName {

    InputStream inputStream = null;
    try {
        inputStream = file.getInputStream();
        // do something with inputStream here....
        inputStream = null;

    } finally {
        if (inputStream != null)
            inputStream.close();
        inputStream = null;
    }

    String extension = FilenameUtils.getExtension( file.getOriginalFilename() );

    final HashMap<String, String> ret = new HashMap<String, String>();
    ret.put( "someInfo", "foobar from uploadImage" );
    return ret;
}
Some interesting things happen here:

  • I also take in another @RequestParam. This is pretty typical of a file upload: to pass more information about the file to the server. Kendo UI's Upload widget's async upload will require a little tweaking to pass in additional information. More on that later.
  • I used MultipartFile::getInputStream() and MultipartFile::getOriginalFile(). These are typical usages of MultipartFile. The entire API is here
  • I also use Apache Commons awesome FilenameUtils and other Commons IO classes. In Java 6 and below, it's still the best way to do IO. When using Commons IO, remember to check if the method closes the stream/file. If not, you have to do it yourself. There are sometimes 2 similar methods to do something: 1 that closes the stream/file, and 1 that doesn't. Do yourself a favor. Use the first one.
  • Finally, I also return a Map. This will translate to an Object when returned back to AngularJS. Not all async uploads require return data. But if you do, here's how you do it. More on that later.

3. Create the Kendo UI Upload widget
Let's take a look at the widget:
<input kendo-upload
       name="file"
       type="file"
       k-multiple="false"
       k-show-file-list="false"
       k-upload="addMorePostParameters"
       k-success="onSuccess"
       k-error="onError"
       k-async="{ saveUrl: 'uploadFile', autoUpload: true }"
        />
In my case:

  • I set k-multiple to false.
  • I also don't want to show the file list
  • k-async contains the URL, and the setting to auto upload the file once the user selects it.
Check out all the configuration on Kendo UI's API page.

How do we pass in the username? That's where k-upload comes in. The API states that the k-upload event "fires when one or more files are about to be uploaded". Let's take a look at the AngularJS code:
$scope.addMorePostParameters = function (e) {
    e.data = {username: "gerard"};
};
The API also says that there is a data object "that will be sent to the save handler in the form of key/value pairs". So we use that to pass in the username String together with the file upload.

How do we access the return value (if any) which the server returned? k-success will do that for you.
$scope.onSuccess = function (e) {
    var someInfo = e.response.someInfo;
};
e.response.someInfo will contain the string "foobar from uploadImage".


I hope that helps.





Programmatically scroll to selected row in Kendo UI Grid widget (using AngularJS)

I had successfully selected a row programmatically in Kendo UI - AngularJS. But because I usually refreshed the data for the Kendo UI Grid, occasionally the selected row would be "scrolled out". So yes, the row was selected, but the user still needed to scroll down to see it.

This was done by using jQuery's scrollTop() method.


  1. First thing we need to do is somehow to get a reference to the Kendo's Grid widget. 
  2. Then we need to get the vertical distance between the Grid "content area" and the selected row.
  3. Finally we call scrollTop() to scroll the grid the above distance.


1. Get a reference to the Kendo's Grid widget
This is very simple.
<div kendo-grid="theGrid"
     k-options="portfolioGridConfig"
     k-data-source="portfolioData"
     k-height="400"
     k-on-change="onUserSelectRow(dataItem)"></div>

Simply specify the variable name in the kendo-grid attribute. Then a simple:
$scope.theGrid
will reference the Kendo widget. Simply simple.


2. get the vertical distance between the Grid "content area" and the selected row
This is done using the offset() jQuery method of the Grid and the selected row. Obtaining the jQuery object of the selected row is outside the scope of this article. I talked about it in a previous post, so you can go take a look. It looks like this:
var row = $('[data-uid=' + item.uid + ']');

Getting the vertical offset of the row from the top of the document then looks like this:
row.offset().top

Now for the vertical offset of the Grid's content area. Looking at the Kendo Grid API, I see that there is a content property "which represents the grid content element, which holds the scrollable content". That's what we want. The vertical offset of the "Grid content element" is then:
$scope.theGrid.content.offset().top

And the vertical difference is just the difference:
row.offset().top - $scope.theGrid.content.offset().top

3. call scrollTop()
Nothing special here. Except if you do a lot of async calls to populate the Grid content. If so, you might find that the Grid content has already been scrolled down. So to be safe, we scroll the Grid content all the way up, then we scroll it back down to the selected item.
var row = $('[data-uid=' + item.uid + ']');

$scope.theGrid.content.scrollTop(0); // we HAVE to reset the scroll first.
$scope.theGrid.content.scrollTop( row.offset().top - $scope.theGrid.content.offset().top );

Conclude
Surely someday Kendo - AngularJS will have a method to do this without resorting to "behind the back" jQuery code. Sooner or later, we'll be free, to leave this all behind. Sooner or later, this is gonna be, the last thing on my mind.

The jQuery docs for scrollTop() and offset() are here.

Tuesday, August 19, 2014

Programmatically Select row in Angular Kendo's Grid

Kendo UI has AngularJs integration. Its mostly working fine but with a few hiccups. One of these hiccups is trying to programmatically select a row in Kendo UI's data grid (call a "grid" in Kendo).

Problem
The Kendo grid has a method select(). Which according to the API:
Gets or sets the table rows (or cells) which are selected.
So I tried to call select in a ng-click directive, and I get an error:
$apply already in progress
Some of you AngularJs experts will already know that $apply() is called by AngularJs to apply changes in the model (aka presentation model), to the view (aka presentation). And it cannot be called recursively; ie. you cannot call $apply() while another $apply is already in progress.

So here's a how my code looked like (the code that gave the "$apply already in progress" error):

<button ng-click="selectRow()">test</button>

And in my controller:
$scope.selectRow = function () {
  // ... some code ...
  $scope.myGrid.select( aRow );
};

After some digging, I found out that almost all code that's in the controller will be in an $apply() call.

  • ng-click="..."
  • ng-blur="..."
  • $scope.$watch(...)
  • $scope.$on(...)
AngularJs docs blame the 3rd party code

Another Problem
And this is Kendo's grid does not have ng-model support. That means you can't do this:

<div kendo-grid
     ng-model="selectedRow"></div>

You have to do this:

<div kendo-grid
     k-on-change="selectedRow = data"></div>

So even if I workaround the first problem above, I can't simply do this in my controller and hope the grid selects the row itself:

$scope.selectRow = function () {
  // ... some code ...
  $scope.selectedRow = aRow;
};


Solution
Apparently the accepted way to do it is 
  1. Wrap the data in a kendo.data.ObservableArray object.
  2. Add the CSS class "k-state-selected" to the row.
  3. Manually update the model with the row.

1. Wrap the data in a kendo.data.ObservableArray object
What this does is to provide true binding of each element of the array to each row of the grid. But a secondary effect of this is to wrap each element of the array in a kendo.data.ObservableObject object. This causes each array element to have a uid field automatically generated. And when the Grid renders, it will add a data-uid attribute to the HTML of the Grid row:

<tr class="k-alt ng-scope" data-uid="ac5be667-5483-4c52-bf2a-3a8f85bb5eeb" role="row">
  ...
</tr>

Perfect.

2. Add the CSS class "k-state-selected" to the row

This is done using jQuery:
$scope.selectRow = function () {
    // ... some code
    // "item" now contains the kendo.data.ObservableObject 
    $('[data-uid=' + item.uid + ']').addClass('k-state-selected');
};


3. Manually update the model with the row

This is done like so

$scope.selectRow = function () {
    // ... some code ...
    $scope.selectedRow = item;
};

So our final selectRow function looks like this:

$scope.selectRow = function () {
    // ... some code ...
    // "item" now contains the kendo.data.ObservableObject 
    $('[data-uid=' + item.uid + ']').addClass('k-state-selected');
    $scope.workingScreenState.selectedRow = item;
};








Monday, August 18, 2014

Add cache control headers to Spring MVC

Many times we want browsers and proxies and gateways to cache our static files. But not the data calls. Here's how to add cache control headers in Spring MVC. 

    <mvc:interceptors>
        <mvc:interceptor>
            <!-- Cache of HTML pages -->
            <mvc:mapping path="/**"/>
            <mvc:exclude-mapping path="/images/**"  />
            <mvc:exclude-mapping path="/webjars/**"  />
            <bean
                    class="org.springframework.web.servlet.mvc.WebContentInterceptor">
                <property name="cacheSeconds" value="0"/>
                <property name="useExpiresHeader" value="true"/>
                <property name="useCacheControlHeader" value="true"/>
                <property name="useCacheControlNoStore" value="true"/>
            </bean>
        </mvc:interceptor>

        <!-- Cache of all images  -->
        <mvc:interceptor>
            <mvc:mapping path="/images/**"/>
            <bean
                    class="org.springframework.web.servlet.mvc.WebContentInterceptor">
                <property name="cacheSeconds" value="1800" />
                <property name="useExpiresHeader" value="true"/>
                <property name="useCacheControlHeader" value="true"/>
                <property name="useCacheControlNoStore" value="true"/>
            </bean>
        </mvc:interceptor>
        <mvc:interceptor>
            <mvc:mapping path="/webjars/**"/>
            <bean
                    class="org.springframework.web.servlet.mvc.WebContentInterceptor">
                <property name="cacheSeconds" value="86400" />
                <property name="useExpiresHeader" value="true"/>
                <property name="useCacheControlHeader" value="true"/>
                <property name="useCacheControlNoStore" value="true"/>
            </bean>
        </mvc:interceptor>
    </mvc:interceptors>



This will create the below HTTP headers:

Pragma: no-cache
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Cache-Control: no-cache
Cache-Control: no-store

This should take care of all the cache problems that we have.

Monday, July 14, 2014

Easy Spring AOP

This article shows how to create aspects in Spring, using Spring AOP.

Quick notes:
  1. Spring AOP is not a fully blown AOP framework (read these few paragraphs). 
  2. It uses AspectJ annotations and pointcut expressions.
  3. Only join point is method execution.
  4. Since Aspects are actually Spring beans, you can inject stuff into it (I prefer using @Autowire for DI).
  5. Spring AOP is a proxy based implementation. This is the most common implementation outside of Spring. Spring will create a proxy for any bean that is being advised. This is called auto-proxying.

Personally always try to use 
  1. Spring's Classpath scanning (aka component scanning)

Ok. To create an aspect I need to:
  1. Create a Spring bean.
  2. Tell Spring that this bean is a Spring AOP aspect
  3. Define the pointcuts. I usually do this in the bean itself, but you can define the pointcuts in its own class.
  4. Define the advices. These will be methods in the bean.

Create a Spring bean
There are many ways to do it. I prefer "annotation-based configuration". So its just a simple annotation (and the xml config to enable annotation-based configuration. I include it here, but its beyond the scope of this document so go read up on it by yourself).

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <mvc:annotation-driven/>
    <context:component-scan base-package="net.gerardsetho.web"/>

</beans>


Here is my MyAnnotationClass. Note the @Component annotation
package net.gerardsetho.web;

import org.springframework.stereotype.Component;

@Component
public class MyAnnotationClass {
}


Tell Spring that this bean is a Spring AOP aspect
So Spring now thinks my class is a normal Spring singleton. We need to tell Spring that its also a Spring AOP aspect. There are 2 ways to do it. I prefer to use "@AspectJ aspects", which Spring recognises. This is done by adding a single line in the XML configuration:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation=".....">

    <mvc:annotation-driven/>
    <context:component-scan base-package="net.gerardsetho.web"/>


    <!--
    This tells Spring to look for AspectJ annotations in the source code, 
    and create aspects for them.
    It also tells Spring to create proxies for (other) beans which are 
    being advised.
    -->
    <aop:aspectj-autoproxy/>

</beans>


Define the pointcuts
I usually define the pointcuts in the Aspect class itself. I guess one could put them in another class, but I rarely needed to do so.

Defining pointcuts is done using the @Pointcut annotation (its an AspectJ annotation). Note that Spring AOP only understand method-invocation join points. So if you need to advise field-get or field-set join points, you need to use a full fledged AOP framework like Aspect J.

Moving on. I usually like to define a pointcut that matches every method in an advised class. 1 pointcut per class. I think it makes things clearer. Then I make another join point for the methods in the class. The code should make this clear.

@Component
@Aspect
public class MyAnnotationClass {


    /**
     * Pointcut that describes all join points (in Spring, 
     * the only join points are method invocations)
     * in the class / interface MyController.
     */
    @Pointcut( "target(net.gerardsetho.web.MyController)")
    private void MyControllerMethods() {}


    /**
     * any method called home,
     * with any number of arguments
     * which returns anything
     */
    @Pointcut( "execution(* home(..))")
    private void entrypoint() {}

}

Here are some examples of other types of pointcuts.


Define the advices
We can combine different pointcuts to define an advice. The below combines (logical AND) the above 2 pointcuts, and creates an advice to print to System.out. It uses @Before, but one can use any number of supported advice types.

    @Before( "MyControllerMethods() && entrypoint()" )
    public void logEntryPoints() {

        System.out.println( "logging entry point." );

    }

In addition to other types of advice, one can also access the parameters of the advised methods. Let me know in the comments if you're interested to know about that.