Showing posts with label ui. Show all posts
Showing posts with label ui. Show all posts

Saturday, November 28, 2015

Groovy framework for AWS lambda

I was playing with AWS lambda recently and I find it pretty exciting. It is cheap, does not require any maintenance and it is simple. The biggest problem I found so far, is lack of tooling. AWS has web UI which does what it supposed to do, but is far from pleasant. AWS command line tools and API are much better, but are AWS centric. So, I have created tool to work with AWS lambda. It uses some convention now, but can be adjusted to whatever feels right for specific situation, idea is that it is just one script with few lines of code. Basically, it does 2 things: uploads application and local testing. I have created small example that illustrates how and what it does.

Example is trivial application that increments number by clicking on button. It is SPA, with static client in S3 and two API functions add and get.

All lambda code is just single Groovy script. It consists of router function, dependencies and logic. Router function is what will be mapped to lambda. It is function that accepts map and returns map. Input map can be plain request JSON, or some additional parameters can be injected at API gateway. Even for this trivial case it was a good idea and I injected configuration parameters - AWS access and secret keys and region for DynamoDB access, so they are hidden at admin level and are environment specific. Simplest way to do routing is just by using some designated parameter, in this example, it is called "function". Doing it with real URI will need AWS configuration, and it is not very convenient and flexible.

In this simple example, router script does logic, but for more complex cases it is better to be just router and logic would be in dependencies.

During packaging Groovy script is compiled and packaged together with all dependencies into uberjar which is required by AWS. After that, it is uploaded via AWS API.

Development can be done and tested locally by using mock server. Mock server mimics AWS, parses input into JSON like lambda, injects parameters like API gateway, includes Access-Control-Allow-Origin and separates configuration via config.js, supports debug and reloading.

Friday, January 2, 2015

CanJS and ClojureScript

I don't really like compiled JavaScript languages, but if I had to choose - I like ClojureScript the most. It is big friends with Om MVC framework, which is based on React.js. React is another component framework like CanJS, but is too verbose to my tastes and has less features out of the box, so I like CanJS more. Only problem is that it does not have a lot of integration with ClojureScript. But it is pretty easy to solve, because ClojureScipt and CanJS are both amazing and flexible. There is example of simple component, there is ClojureScript:

(ns myexample
  (:require [domina :refer [by-id set-html!]]
            [domina.css :refer [sel]]))

(.extend can/Component
  #js {:tag "my-component"
       :scope #js {:value 3
                   :increment #(.attr % "value" (inc (.attr % "value")))}})

(set-html! (by-id "my-root") (can/view "my-template" {}))


And HTML:

<html>
<body>
  <div id="my-root"></div>
  <script type="text/mustache" id="my-template">
    <my-component>
      Value: {{value}} <input type="button" can-click="increment" value="Increment"/>
    </my-component>
  </script>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.js"></script>
  <script src="http://canjs.com/release/latest/can.jquery.js"></script>
  <script src="base.js" type="text/javascript"></script>
  <script src="myexample.js" type="text/javascript"></script>
  <script type="text/javascript">goog.require("myexample");</script>
</body>
</html>



Friday, December 19, 2014

Sending data to CanJS component

Ideally, components should be independent, but sometimes it is needed to send data or call function on component from outside. It is possible to do by using observable like can.Map and listen to events on it from component like:

<script type="text/javascript">
  var observable = new can.Map({val:0});

  $(function() {
    can.Component.extend({
      tag: "my-tag",
      events: {
        "{observable} val": function(param, param2, newval){
          alert(newval);
        }
      }
    });
    $('#myTagDiv').html(can.view.mustache('<my-tag/>'));
  });
</script>



<div id="myTagDiv"></div>
<input type="button" value="Call observable" onclick="observable.attr('val', observable.val+1);">


This way all components will receive observable change event either they are sent from itself, other component or directly from JavaScript.

Tuesday, July 22, 2014

CanJS execute code on component initialization

I didn't found it described anywhere, but it works for me. If you need to execute code after component initialization, you can add init method to scope and it is executed after component is created.

    scope: {
      init: function() {
        runme();
      }
    }

Thursday, July 3, 2014

Updating model elements of CanJS component scope

CanJS scope is simple map and when you need to retrieve new element from server the easiest way seems just to assign new model to property, like:

  scope.attr('todos', new Todo.List({date:val}));

This is easy and works, but not best solution, as values blink on screen. This is because initial list is empty and values are added after they are loaded, so more smooth and reactive (bazinga!) way to do it, will be by model's findAll method callback, like:

  Todo.findAll({date:val}, function(todos){ scope.attr('todos', todos) });

Additional benefit of this approach is that you can use new values for whatever you might need besides displaying them.

Thursday, June 12, 2014

CanJS is not calling Mustache function when value is updated

Mustache can map not only specific values to template, but also results of the functions, which is sometimes handy. There is example.

But recently, when I was using this feature inside of CanJS template, it only rendered results for the first time and did nothing when values were changing. This was not working properly:

  can.Component.extend({
    tag: "sum",
    scope: {
      model: new can.Model({x: 2, y:3}),
      result: function() {
        return this.model.x * this.model.y;
      }
    },
    template: '<input can-value="model.x">*<input can-value="model.y">={{result}}'
  });

As I found out, problem was that it was missing proper value invocation and simply calling values via attr method fixes the problem.
This works fine:

  can.Component.extend({
    tag: "sum",
    scope: {
      model: new can.Model({x: 2, y:3}),
      result: function() {
        return this.model.attr('x') * this.model.attr('y');
      }
    },
    template: '<input can-value="model.x">*<input can-value="model.y">={{result}}'
  });

Wednesday, June 4, 2014

Accessing multiple objects from CanJS events in components

CanJS components have nice and easy way to access context object from event, just as parameter:

{{#books}}
  <input type="button" can-click="add" />
{{/books}}

add: function(book) {
  books.add(book);
}

But what if you need also parent object, or object from some other hierarchy. To do it, CanJS can bind DOM objects to any data, and in components this is usually context. Just add special property {{data '...'}} to DOM element in your Mustache template, for example:

{{#shelves}}
  <h1>{{name}}</h1>
  <div {{data 'shelf'}}>
    {{#books}}
      <input type="button" can-click="add" {{data 'book'}} />
    {{/books}}
  </div>
{{/shelves}}

And you can access all objects like:

add: function(context, el) {
  var book = el.data('book');
  var shelf = el.parent().data('shelf');
  shelf.add(book);
}

Thursday, May 29, 2014

Grabing JavaScript libraries via WebJars in Spring Boot

WebJars is nice and familiar way to work with JavaScript dependencies from Java projects. Spring Boot supports it, and it is pretty easy to add them for Groovy projects, just with good old Grab annotation, like:

@Grab("org.webjars:canjs:2.0.2")

Then all CanJS files become available under /webjars/canjs/2.0.2/. If not sure, list of files can be looked up at WebJars website.

Friday, May 9, 2014

Chaining jQuery promises in for cycle

JQuery has nice support for promises, but some stuff is not obvious and recently I just stuck with one particular problem: I had to prepare a bunch of closures in for cycle and added them to deferred object which was resolved afterwards. All of them had to be executed strictly one after another, but there are ajax calls so I cann't do it old fashioned way, since sinchronous ajax is weird.
So I did this:

function doPromise(someVar) {
  return function() {
    return $.ajax({ type: 'POST', url: 'http://myurl', success: doStuff, error: panic});
  }
};
function start() {
  var promise = $.Deferred();
  for (var i=0;i<10;i++) {
    promise.then(doPromise(i) );
  }
  promise.resolve();
};


And I was expecting it being called one after another, which was not the case and all of them fired simultaniously. As I found out finally, all thens are equal and I had to add them, not to original promise, but dirrectly to each other, which is a little confusing to me, but works. So this is the correct code for my case:

function start() {
  var original = $.Deferred();
  var promise = original;
  for (var i=0;i<10;i++) {
    promise = promise.then(doPromise(i) );
  }
  original.resolve();
};


Tuesday, April 15, 2014

IllegalStateException Method on class was used outside of a Grails application

After upgrade to 2.3 and running Geb functional UI tests, they started to fail with error:

java.lang.IllegalStateException: Method on class [my.Test] was used outside of a Grails application. If running in the context of a test using the mocking API or bootstrap Grails correctly.
       at my.Test.currentGormStaticApi(Test.groovy)
       at my.Test.$static_methodMissing(Test.groovy)
       at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
       at groovy.lang.MetaClassImpl.invokeStaticMissingMethod(MetaClassImpl.java:1372)
       at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1360)
       at groovy.lang.ExpandoMetaClass.invokeStaticMethod(ExpandoMetaClass.java:1123)
       at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.call(StaticMetaClassSite.java:50)
       at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
       at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
       at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)


After some pretty painful investigation, I found out that problem is when running tests with new fork mode properties, and is easy to solve by removing these options from BuildConfig.groovy:

grails.project.fork = [
    test: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, daemon:true],
    run: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, forkReserve:false],
    war: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, forkReserve:false],
    console: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256]
]

Thursday, April 3, 2014

MeteorJS like application in Grails

MeteorJS is new web framework that combines server-side and client-side programming into one, leaving mostly just client-side. I am defenitely not expert with tool and just seen demo on their homepage, but WOW effect is sure impressive. It suppose to kill all Rails and server-side development in general. Thank god I am full-stack developer, but anyway I am scared.

General idea behind this framework is autogenerating all server-side code, leaving mostly just configuration. Similar feature was recently introduced in Grails, so I was wondering - is it possible to create something similar to MeteorJS in Grails. And there is my experience.

Basically, it needs autogenerated REST, Javascript ORM and server push. REST is Grails feature since version 2.3; for client-side ORM I picked CanJS as it looks most similar to Meteor; for server push in Grails I picked spring-websocket plugin (because it is first result in Google, why else?). Unfortunately, spring-websocket is M1 and it relies on Spring 4, so Grails is 2.4M1 too, so it is not production safe, but MeteorJS is 0.8.0 now too, so we are even.

Application idea is simple TODO app. You can find full source here. There is defenitely some boilerplate code as it is not plugin, but I think in general it is pretty similar to MeteorJS example. It consists of 3 meaningful components: view, controller and domain object.

View is Mustache template, and is pretty straightforward if you are familiar with CanJS:

<h1>test</h1>
<table>
{{#todos}}
  <tr>
    <td>{{description}}</td><td><input type="checkbox" can-value="done"></td>
    <td><input type="button" value="Delete" can-click="delete"></td>
    </tr>
{{/todos}}
</table>

Description
<input type="text" can-value="description">
<input type="button" can-click="add" value="Add">

Controller is CanJS component with ORM definition:

var Todo = can.Model({
  findAll: function(id)   {return $.get('/grails-meteor-example/todos.json/')},
  findOne: function(id)   {return $.get('/grails-meteor-example/todos.json/'+id)},
  create:  function(data) {return $.post('/grails-meteor-example/todos.json/', data)},
  update:  function(id)   {return $.ajax({type: 'PUT',    url: '/grails-meteor-example/todos.json/'+id })},
  destroy: function(id)   {return $.ajax({type: 'DELETE', url: '/grails-meteor-example/todos/'+id, contentType: 'application/json' })}
}, {});

can.Component.extend({
  tag: "todos",
  template: can.view("todos.mustache"),
  scope: {
    todos: new Todo.List({}),
    description: can.compute(''),
    add: function() {
      new Todo({'description':this.description(), 'done':false}).save();
      this.description('');
    },
    delete: function(todo) {
      todo.destroy();
    }
  },
  events: {
    "{todo} change": function(){
      this.scope.attr('todos', new Todo.List({}));
    }
  }
});

$(document).ready(function() {
  $("body").html( can.view.mustache("<todos></todos>"));
});


Domain is Grails domain object mapped as REST controller:

package org.grmeteor

import grails.rest.Resource

@Resource(uri='/todos')
class Todo {
  String description
  boolean done
}


View is totally similar to MeteorJS. Controller is similar, but also contains ORM definition and server push event. Both could be easily autogenerated with Grails plugin, but at least push can be also left for practical applications (probably, you will not want to have notification with millions of parallel users). Domain is pure Grails overhead, but it would probably still be needed for SQL backends in MeteorJS (and hey, those server-side devs want to eat too!).

Of course there are other files too, like server push sender and client side HTML container for CanJS, but these are mostly static and sure can be easily hidden by plugin. So only part that is missing to make Grails MeteorJS-cool is plugin itself, which even if not for practical cases could be nice to have for WOW effect and MVPs.

Wednesday, April 2, 2014

Grails REST redirect after DELETE with jQuery

If you do delete from AJAX request (directly or via framework), sometimes Grails REST controller redirects response to index method, which when done with DELETE method leads to 405 HTTP error.
This happens because of incorrect content type in request. To fix it, contentType needs to be explicitly set in request, like:

$.ajax({
    url: '/todos/'+id,
    type: 'DELETE',
    contentType: 'application/json'
  })

Thursday, March 20, 2014

CanJS incorrectly places elements in table row

After rendering this HTML in CanJS, 'tests' elements got placed before table and not after previous cell as it is supposed to be:

<thead>
  <tr>
    <th>Test</th>
    <th><input type="button" value="Test"></th>
    {{#tests}}
      <th>{{name}}</th>
    {{/tests}}
  </tr>
</thead>

Problem was that input tag was not closed, which is usually fine with HTML, but confuses CanJS. After closing it, everything was working as expected.

Friday, December 20, 2013

Access to services from gsp views in Grails

Accessing services from views is considered bad practice, so there is no easy way to do it. It defenitely should not be overused, as it complicates testing and couples logic with presentation. However it is not necessary crime and can be handy for some cases.

For example, if you need access to user parameters. Traditional way to do it, is by using taglibs. What is less known is that you can use taglibs not just to produce text output, but also inside snippets of code in views. For example, you can use it to select users preferred language without need to inject it into every controller:

Taglib:

class UserSettingsTagLib {
    def springSecurityService

    def myLanguage = { attrs, body ->
      out << springSecurityService.currentUser?.myLanguage?.id
    }

}


Gsp:

<g:select name="language" optionKey="id" optionValue="name" value="${g.myLanguage()}" from="${Language.list().sort{it.name}}"/>


Wednesday, April 10, 2013

Setting style by custom property dynamically in AngularJS

Angular JS lets to set and update style and class based on some custom property. Unfortunately, it does not support placeholders now, for example:


<!-- This works -->
<td ng-style="myStyle">


<!-- This does not -->
<td ng-style="myStyle{{test}}">



Fortunately, it works with controller's methods, so this still can be done like:


<td ng-style="getMyStyle(test)">

where getMyStyle is controller's method.

Friday, January 25, 2013

grails-coffeescript-resources is not working after deploying war in production

There is great Grails plugin that allows to work with CoffeeScript very easily, compiles .coffee files on the fly and does all dirty work.
However, once I tried to deploy my application to test environment, all CoffeeScript files became available in browser as is, without compilation. After some investigation I found out that problem is that it does not supports applications deployed as packed WAR files (with unpackWARs="false" in server.xml), it was pretty easy to fix by modifying plugin script grails-app/resourceMappers/CoffeeScriptResourceMapper.groovy by changing:
 
      File input = grailsApplication.parentContext.getResource(resource.sourceUrl).file

to this

      File input
      try {
        input = grailsApplication.parentContext.getResource(resource.sourceUrl).file
      } catch (FileNotFoundException e) {
        input = new File(original.absolutePath)
      }


and it should work.
One problem is that this change is inside plugin, so you can't do change in your code, and should change plugin itself. I submitted fix with pull request on GitHub, hopefully it will be merged. Until then it is possible to compile your own version from here, or just replace this one line on build server.


Friday, March 16, 2012

JavaScript unit testing in Grails

Recently I wanted to test some complicated JavaScript code and surprisingly there is no a lot of options to choose from in Grails. Fortunately, I was already using Geb and it is extremely easy in this case.
I decided to use QUnit testing framework and all that needs to be done in this case is to place few static files in JS, CSS and HTML folders, create Geb page for QUnit reports and Geb Spec for launching browser. For development everything can be done (and much faster) with QUnit alone. Geb is basically only needed to run tests from CI (Jenkins in my case).


There is my Geb Spec:

package my.test.specs

import spock.lang.Stepwise
import my.test.pages.QUnitPage

@Stepwise
class QUnitSpec extends GebScreenshotsSpec {

  def "run QUnit tests"() {
    when:
    to QUnitPage

    then:
    at QUnitPage
    failedCount == '0'
  }

}


Geb page:

package my.test.pages

import geb.Page

class QUnitPage extends Page {
  static url = "http://localhost:"+System.getProperty("server.port", "8080")+"/my-test/js/tests/qunit.html"

  static at = { $("#qunit-header") }

  static content = {
    failedCount(wait:true) {$('#qunit-testresult .failed').text()}
  }
}


qunit.html and all it's content is just plain QUnit framework.

Disadvantages are that reports are not persisted or summarized with other testing frameworks, but if you have screenshots in your Geb tests, it will provide some feedback. Another issue is if you are not using Geb, than this can be overkill to use it only for JS unit tests.
But in case you already have Geb this is super-simple and lightweight approach.

Friday, February 10, 2012

JavaScript parseInt does not work as expected when parameter starts with 0

There is standard way to parse Strings into Numbers in JavaScript by using parseInt function. But sometimes it works unexpected, and for example, returns 0 when you expect 8. If that is the case, then most probably problem is that when parameter starts with 0 (like '08') parseInt treats it as octal number and changes radix to 8.
This is annoying and can take some time to discover. Luckily, it is easy to fix by specifying radix directly as second parameter. For example like:

parseInt('08', 10)




Friday, February 3, 2012

Freezing table header with JQuery

When you have long table on page, with a lot of numbers, and you scroll down and header is not visible anymore, it is often difficult to track what number is which column. One nice solution to this problem is to lock and freeze table header when scrolling page.
Unfortunately there is no ready out of the box solution with JQuery for this problem. Fortunately, it is easy to implement with few methods. There are examples how to do it, but for some reason they didn't worked well in my situation (no support for resize and horizontal scroll), so I have adjusted them for my situation.

For example, you have your table named tabs.

First, you have to create invisible table that will hold frozen header.

<table cellpadding='0' cellspacing='0' id="header-fixed"  style="position: fixed; top: 0px; display:none;"></table>

Then just add this Javascript:

     <script type="text/javascript">
       var tableOffset;
       var header;
       var fixedHeader;

       function resize() {
         var totalwidth = $('#tabs').css('width');
         fixedHeader.css('width', totalwidth);
         var widths = [];
         $('#tabs thead th').each(function() {
           widths.push($(this).width());
         });
         var i=0;
         $('#header-fixed th').each(function() {
           this.width = widths[i];
           i++;
         });
       }
       function resizeAndShow() {
         var offset = $(this).scrollTop();
         if (offset >= tableOffset && fixedHeader.is(":hidden")) {
           fixedHeader.show();
           resize();
         } else if (offset < tableOffset) {
           fixedHeader.hide();
         }
         fixedHeader.css('left', $('#tabs').position().left - $(this).scrollLeft());
       };
        $(document).ready(function() {
          tableOffset = $("#tabs").offset().top;
          header = $("#tabs > thead").clone();
          fixedHeader = $("#header-fixed").append(header);

          $(window).bind("scroll", resizeAndShow);
          $(window).resize(resize);
        });
     </script>

This is it.

Thursday, January 5, 2012

Getting text of selected option in Geb

Geb has very nice function to get value of selected option, but I was not able to find method to get it's text. Fortunately, it is still possible using ugly Selenium API and can be nicely hidden behind Page Object. For example, this is what I have in my Page Object:

myField {$("#my") }
myFieldValue {  new Select($("#my").getElement(0)).getFirstSelectedOption().getText() }

And this is how it looks in Spec:

when:
myField.value('B')

then:
myFieldValue == 'B'