Sunday, March 2, 2014

Html element content change event

You could add some custom event to see effect change of the content of the element:
You can see this example here at jsFiddle: Html element content change event 
 

Html content


<table>
    <tr>
        <td valign="top">
           <button id="html">Click to see change 'html'.</button><br/>
           <button id="append">Click to see change 'append'.</button><br/>
           <button id="prepend">Click to see change 'prepend'.</button><br/>
           <div id="hello">This is text!</div>
        </td>
        <td valign="top">
            <div id="console"></div>
        </td>
    </tr>
</table>


jQuery content


// Redefines $.fn.html(), $.fn.append(), $.fn.prepend() to add custom events that are triggered before and after a DOM element's innerHtml is changed
// html-change-pre is triggered before the innerHtml is changed
// html-change-post is triggered after the innerHtml is changed

(function($) {
    var eventName = 'html-change';
    // Save a reference to the original html, append and prepend function
    $.fn.htmlx = $.fn.html;
    $.fn.appendx = $.fn.append;
    $.fn.prependx = $.fn.prepend;
    // Let's redefine the html, append and prepend function to include a custom event
    $.fn.html = function() {
        var currentHtml = this.htmlx();
        if(arguments.length) {
            this.trigger(eventName + '-pre', jQuery.merge([currentHtml], arguments));
            jQuery.fn.htmlx.apply(this, arguments);
            this.trigger(eventName + '-post', jQuery.merge([currentHtml], arguments));
            return this;
        } else {
            return currentHtml;
        }
    }
    $.fn.append = function() {
        var currentHtml = this.htmlx();
        if(arguments.length) {
            this.trigger(eventName + '-pre', jQuery.merge([currentHtml], arguments));
            jQuery.fn.appendx.apply(this, arguments);
            this.trigger(eventName + '-post', jQuery.merge([currentHtml], arguments));
            return this;
        } else {
            return currentHtml;
        }
    }
    $.fn.prepend = function() {
        var currentHtml = this.htmlx();
        if(arguments.length) {
            this.trigger(eventName + '-pre', jQuery.merge([currentHtml], arguments));
            jQuery.fn.prependx.apply(this, arguments);
            this.trigger(eventName + '-post', jQuery.merge([currentHtml], arguments));
            return this;
        } else {
            return currentHtml;
        }
    }
})(jQuery);
        
// Test
jQuery(document).ready(function() {

    jQuery('#hello').bind('html-change-pre', function() {
        $("#console").prepend('<div>html-change-pre triggered: '+counter+'</div>');
    });
    
    jQuery('#hello').bind('html-change-post', function() {
        $("#console").prepend('<div>html-change-post triggered: '+counter+'</div>');
    });
    var counter = 0;
    $("#html").click(function() {
        $("div#hello").html("<div>html: "+counter+"</div>");
        counter++;
    });
    $("#prepend").click(function() {
        $("div#hello").prepend("<div>prepend: "+counter+"</div>");
        counter++;
    });
    $("#append").click(function() {
        $("div#hello").append("<div>append: "+counter+"</div>");
        counter++;
    });
});

Example output at jsFiddle:


jQuery remove and restore element events

jsFiddle Link

function toggleEvent(id) {
    var target = $(id);
    var events = $._data(target[0], 'events');
    if(events!=undefined){    //  if the element has event || target = element
        target[0].event_name = [];
        target[0].event_handler = [];        
        $.each(events, function(event_name, event_handler) {
            target[0].event_name.push(event_name);
            var _handlers=[];
            for(var i=0;i<event_handler.length;i++){
                _handlers.push(event_handler[i].handler);
            }
            target[0].event_handler.push(_handlers);          
        });  //store the events
        target.off();  // delete the events
    }else{    // has the elment no event
        for(var i=0; i < target[0].event_handler.length; i++){
            for(var ii=0;ii<target[0].event_handler[i].length;ii++){
                target.on(target[0].event_name[i], target[0].event_handler[i][ii]);
            }          
        }  // re-store the events
        target[0].event_name = [];
        target[0].event_handler = [];  //reset
    }
}

$("#a").click(function() {
    alert("Event in action");
});

var eventInAction = true;
$("#b").click(function(){
    toggleEvent('#a');
    if(eventInAction) {
        eventInAction = false;
        $(this).html("Add events to button 'A'");
    } else {
        eventInAction = true;
        $(this).html("Remove events from button 'A'");
    }
});

Thursday, February 27, 2014

Binding a Grails date from params in a controller

Add the following lines in 'Config.groovy' file


grails.databinding.trimStrings=true
grails.databinding.convertEmptyStringsToNull=true
grails.databinding.dateFormats = ['yyyy-MM-dd HH:mm:ss.S', 'yyyy-MM-dd', "yyyy-MM-dd'T'hh:mm:ss'Z'"]

First line triming all string values on data binding to domain instance.
Second line convert all empty string to null.
And third line accept the date formats provided to convert it to date.

Or you can use those as following:


package com.pkm.test.domains

import org.grails.databinding.BindingFormat

class TestOne {
    Long id
    String name;
    String display;
    @BindingFormat("yyyy-mm-dd")
    Date created;

    static constraints = {
        display(nullable: true)
    }
}

And from controller


params.name = "YES-Pritom K Mondal";
params.display = " ";
params.created = "2014-02-27";
TestOne testOne = new TestOne();
DataBindingUtils.bindObjectToInstance(testOne, params)
testOne.save(failOnError: true);

Will create a following row in the table


Field 'display' is null because value from controller: ' ' first trim() and then convert empty string to null according to Config.groovy settings above.

Sunday, February 23, 2014

jQuery Change Event: Proper Binding


$("input[name='name']").on("input", function(event) {
    $("div").prepend("Text: " + $(this).val() + "<br/>");
});

// or

<input type='text' name='name' oninput='$(this).changeOccurs()'/>

and in jquery:
jQuery.fn.changeOccurs = function () {
    // do something you wish to do.
};

jsFiddle link

Wednesday, February 19, 2014

Groovy template engine

Included with Groovy are several template engines:
  • SimpleTemplateEngine - for basic templates
  • GStringTemplateEngine - stores the template as writable closures (useful for streaming scenarios)
  • XmlTemplateEngine - works well when the template and output are valid XML

SimpleTemplateEngine


import groovy.text.SimpleTemplateEngine

def text = 'Dear ${contact.firstName} ${contact.lastName}${contact.nickName? " " + contact.nickName: ""}.\n${time} is good.'

def binding = ["time":"this evening", month: "February", "contact": ["firstName": "Pritom", "lastName": "Mondal", age: 27]]

def engine = new SimpleTemplateEngine()

def template = engine.createTemplate(text).make(binding)

println template.toString();
Output
Dear Pritom Mondal.
this evening is good.

GStringTemplateEngine


import groovy.text.GStringTemplateEngine

File templateFile = new File("web-app/test.txt");
def templateEngine = new GStringTemplateEngine();
def templateObject = templateEngine.createTemplate(templateFile).make(binding);
println templateObject.toString();
File content
Dear ${contact.firstName} ${contact.lastName},
So nice to meet you in <% out << (time == "this evening" ? "\"${time}\"" : "\"this morning\"") %>.
So nice to meet you in <% out << (time == "this evening" ? "\"this morning\"" : time) %>.
See you in ${month?: ""}
Output
Dear Pritom Mondal,
So nice to meet you in "this evening".
So nice to meet you in "this morning".
See you in February

Tuesday, February 18, 2014

Check the validity of an HTML5 form that does not contain a submit button


/* Check if html5 validation enabled */
function hasHtml5Validation () {
    return typeof document.createElement('input').checkValidity === 'function';
}


var $form = $("form");
$form.find("input.save-and-next").click(function() {
    $form.find(":input").each(function() {
        //if(!$(this).checkValidity()) {
        if(!$(this)[0].checkValidity()) {            
            $form.find("input[type='submit']").click();
            return false;
        }
    });
});

When you select  $(this) you get a collection of nodes, to access actual DOM properties you must select the numbered one such $(this)[0].

Or you can bind validation process to a form field such as:

form.find("input[type='text']").keyup(function() {
    if(!$(this)[0].checkValidity()) {
        form.find("input[type='submit']").click();
    }
});

Hooking into GORM custom event listener from plugin in Grails

In our custom listener, the method ‘onPersistenceEvent’ is called on all GORM events that we filter to what we interested – PreInsert, PreUpdate
Create a groovy file under src/groovy suppose named 'FieldValidationListener.groovy' with the following contents. And create required method in your domain class, suppose one method can be named: 'doValidationPreInsert' or 'doValidationPreUpdate'.

package com.groovy.fieldSetting

import grails.util.Holders
import org.codehaus.groovy.grails.commons.GrailsApplication
import org.grails.datastore.mapping.core.Datastore
import org.grails.datastore.mapping.engine.event.*
import org.springframework.context.ApplicationEvent

/**
 * Created by pritom on 17/02/14.
 */
class FieldValidationListener extends AbstractPersistenceEventListener {
    public FieldValidationListener(Datastore datastore) {
        super(datastore)
    }

    @Override
    protected void onPersistenceEvent(AbstractPersistenceEvent event) {
        String operation;
        switch (event.eventType) {
            case EventType.PreInsert:
                operation = "PreInsert"
                break;
            case EventType.PreUpdate:
                operation = "PreUpdate"
                break;
        }
        if(operation) {
            String methodName = "doValidation${operation}"
            println "Searching for method: ${methodName}"
            if (event.entityObject.respondsTo(methodName)) {
                try {
                    event.entityObject."${methodName}"()
                } catch (Exception exp) {
                    event.cancel();
                    throw exp;
                }
            }
        }
    }

    @Override
    boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
        if ([PreInsertEvent, PreUpdateEvent].any { def supportedType ->
            if (supportedType.isAssignableFrom(eventType)) {
                return true
            } else {
                return false
            }
        }) {
            return true
        } else {
            return false
        }
    }

    public static void initialize(GrailsApplication application) {
        application.mainContext.eventTriggeringInterceptor.datastores.each { k, datastore ->
            Holders.applicationContext.addApplicationListener(new FieldValidationListener(datastore))
        }
    }
}

And initialize start listening, insert the following code block into 'BootStrap.groovy' [in 'init' method]:

FieldValidationListener.initialize(grailsApplication)