Backbone – Acceder a los objetos de una colección en una plantilla de Handlebars

Para acceder a los objetos de una colección en una plantilla de Handlebars tienes que pasar dichos objetos como un parámetro a la función template. Si utilizas Backbone y tu colección de objetos es una colección de modelos, puedes utilizar la función toJSON para convertirlos en objetos javascript y que puedan ser interpretados por Handlebars.

Supongamos que tenemos los siguientes objetos (modelos)

app.models.Equipo = Backbone.Model.extend({

    initialize: function () {

    },

    sync: function (method, model, options) {
    if (method === 'read') {
        app.adapters.equipos.findById(parseInt(this.id)).done(function (data) {
            options.success(data)
        })
    }
    }
})

app.models.EquipoCollection = Backbone.Collection.extend({

    model: app.models.Equipo,

    sync: function (method, model, options) {
    if (method === 'read') {
        app.adapters.equipos.findAll().done(function(data){
            options.success(data)
        })
    }
    }
})

y nuestra plantilla es la siguiente

    <div class="row">
        {{#each equipos}}
        <div class="col-6">
            <a href="equipos/#{{name}}" class="thumbnail text-center">
                <img src="{{logoUrl}}"/>
            </a>
        </div>
        {{/each}}
    </div>

Entonces para pasar nuestros objetos a la plantilla, lo haríamos de la siguiente manera

app.views.EquiposListView = Backbone.View.extend({
    initialize: function(){
        this.equipos = new app.models.EquipoCollection()
        this.equipos.on('reset', this.render, this)
        this.equipos.fetch({reset: true})
    },

    render: function(){
        this.$el.html(this.template({equipos: this.equipos.toJSON()}))
        return this
    }

})

Notesé el uso de la función toJSON

Fuentes:
http://stackoverflow.com/questions/12439471/rendering-handlebars-template-with-backbone
http://stackoverflow.com/questions/14170298/how-to-access-backbone-model-properties-in-a-handlebar-template

Anuncios

Jackson JSON – Deserializar un array en una petición REST

En un servicio REST (jax-rs) puedes enviar los parámetros de una petición de varias formas: en la URL (@QueryParam), en el cuerpo del mensaje con el encabezado “application/x-www-form-urlencoded” (@FormParam), como parte de la URL (@PathParam).

Pero que pasa si el cliente envía toda la información en el cuerpo del mensaje en formato JSON.
Por ejemplo:

    {
        "tipo":"URGENTE",
        "actores":[
        {
            "nombre":"Juan",
            "apellidos":"Peréz",
            "idEstado":null,
            "idMunicipio":null,
            "idColonia":null,
            "calle":"Calle 2",
            "numero":"155",
            "codigoPostal":"76800"
        }
        ],
        "demandados":[
        {
            "nombre":"María",
            "apellidos":"López",
            "idEstado":null,
            "idMunicipio":null,
            "idColonia":null,
            "calle":"Calle 4",
            "numero":"45",
            "codigoPostal":"76800"
        }
        ]
    }

Podríamos crear una clase que reflejará esta estructura, pero si solo nos interesa algún campo o la petición no tiene nada que ver con nuestro modelo, no parece la mejor opción.

En este caso, en nuestro modelo existiría una clase Actor y Demandado que comparten los mismos campos, por lo que podríamos usar la herencia.

    public class Parte {
        String id;
        String nombre;
        String apellidos;
        String idEstado;
        String idMunicipio;
        String idColonia;
        String calle;
        String numero;
        String codigoPostal;
        public Parte() {
        }
        //... getter's y setter's, métodos, etc.
    }
    public class Actor extends Parte{
        //... otras propiedades
        public Actor() {
        }
        //... otros métodos
    }
    public class Demandado extends Parte{
        //... otras propiedades
        public Actor() {
        }
        //... otros métodos
    }

en nuestro servicio REST (Apache CXF) podríamos deserializar el arreglo de Actores de la siguiente forma

    @Path("solicitar/")
    public String solicitar(String data){
        String response = null;
        try{
            ObjectMapper mapper=new ObjectMapper();
            mapper.configure(SerializationConfig.Feature.WRITE<em>DATES</em>AS<em>TIMESTAMPS, false);
            mapper.configure(Feature.FAIL</em>ON<em>UNKNOWN</em>PROPERTIES, false);
            Map<String, Object> map = mapper.readValue(data, new TypeReference<Map<String, Object>>(){});
            String tipo = (String) map.get("tipo");
            List
<Parte> actores = mapper.convertValue(map.get("actores"), new TypeReference
<List<Parte>>() {});
            //... registrar la solicitud
            response = mapper.writeValueAsString(actores);
        }catch(Exception e){
            String error = "Ocurrió un problema al hacer la solicitud";
            log.error(error, e);
            response = String.format("{\"response\":{\"status\": -1, \"data\": \"%s\"}}", error);
        }
        return response;
    }

Fuentes:
http://wiki.fasterxml.com/JacksonDataBinding
http://cxf.apache.org/docs/jax-rs-basics.html#JAX-RSBasics-DealingwithParameters

Datanucleus (JDO) – Relaciones y propiedades de tipo objeto

En datanucleus existe un mecanismo llamado attach/detach que sirve para acceder a las propiedades de los objetos fuera del contexto de una transacción. Esto es muy útil, por ejemplo, cuando estructuras tu aplicación en librerías o capas.

Supongamos que tenemos la siguiente clase

    @PersistenceCapable
    public class Audiencia {</p><pre><code>    @PrimaryKey
    @Persistent
    Integer id;
    @Persistent
    Juez juez;
    @Persistent
    Date inicio;
    @Persistent
    Date fin;
    @Persistent
    TipoAudiencia tipo;

    public Audiencia(){
    }

    public static List&lt;Audiencia&gt; getAudiencias(Integer idJuez) {
        List&lt;Audiencia&gt; audiencias;
        PersistenceManager pm = PMF.get().getPersistenceManager();
        Transaction tx = pm.currentTransaction();
        try{
            tx.begin();
            String filter = "juez.id == :idJuez";
            Query query = pm.newQuery(Audiencia.class, filter);
            audiencias = (List&lt;Audiencia&gt;) pm.detachCopyAll((List&lt;Audiencia&gt;)query.executeWithArray(idJuez));
            tx.commit();
        }finally{
            if(tx.isActive()){
                tx.rollback();
            }
            pm.close();
        }
        return audiencias;
    }

}
</code></pre><p>

cabe destacar que dentro del contexto de la transacción podríamos leer las propiedades Juez y TipoAudiencia, datanucleus cargaría los objetos relacionados de forma “lazy loading”. Pero si trataramos de leer alguna propiedad fuera de este contexto -es el caso cuando ejecutamos el método getAudiencias desde otra clase- está tendría el valor null. Datanucleus sólo hace el detach de las propiedades en el Default Fetch Group. Para poder utilizar las demás propiedades, podemos especificar un Fetch Group dinámico de la siguiente manera

    public static List getAudiencias(Integer idJuez, String[] fields) {
        List audiencias;
        PersistenceManager pm = PMF.get().getPersistenceManager();
        Transaction tx = pm.currentTransaction();
        try{
            tx.begin();
            FetchGroup fetchGroup = PMF.get().getFetchGroup(Audiencia.class, "fields");
            fetchGroup.addMembers(fields);
            pm.getFetchPlan().addGroup("fields");
            String filter = "juez.id == :idJuez";
            Query query = pm.newQuery(Audiencia.class, filter);
            audiencias = (List) pm.detachCopyAll((List)query.executeWithArray(idJuez));
            tx.commit();
        }finally{
            if(tx.isActive()){
                tx.rollback();
            }
            pm.close();
        }
        return audiencias;
    }

Fuentes:
http://www.datanucleus.org/products/accessplatform/jdo/fetchgroup.html
http://www.datanucleus.org/products/datanucleus/jdo/attachdetach.html
http://www.datanucleus.org/products/datanucleus/jdo/object
lifecycle.html

GWT – JSON dates

JSON no tiene un tipo de dato Date, así que cuando transfieres fechas mediante JSON debes convenir un formato de fecha -por ejemplo, yyyy-MM-dd’T’hh:mm:ss.SZ- Un ejemplo de fecha en este formato sería “2013-03-08T16:23:35.000+0000”.

Para facilitar un poco las cosas, decidí utilizar un Overlay Type para la representación de mi objeto y acceder a sus propiedades mediante getter’s y setter’s. Estos métodos realizan la conversión de cadena a fecha, y viceversa, con la ayuda de la clase DateTimeFormat.

    public class Audiencia extends JavaScriptObject {</p><pre><code>    private final static DateTimeFormat dateTimeFormat = DateTimeFormat.getFormat("yyyy-MM-dd'T'hh:mm:ss.SZ");

    public final native int getId()/*-{
        return this.id;
    }-*/;

    public final Date getInicio(){
        return dateTimeFormat.parseStrict(getInicioNative());
    };

    private final native String getInicioNative()/*-{
        return this.inicio;
    }-*/;

    public final Date getFin(){
        return dateTimeFormat.parseStrict(getFinNative());
    };

    private final native String getFinNative()/*-{
        return this.fin;
    }-*/;

    protected Audiencia() {
    }

    public static void getAudiencias(String idSala,
            final AsyncCallback&lt;Audiencia[]&gt; callback) {
        try {
            String queryParams = "?sala="+URL.encodeQueryString(idSala);
            RequestBuilder rb = new RequestBuilder(RequestBuilder.GET,
                    Consts.REST_AUDIENCIAS + queryParams);
            rb.sendRequest(null, new RequestCallback() {

                @Override
                public void onResponseReceived(Request request,
                        Response response) {
                    if(response.getStatusCode() == 200){
                        JavaScriptObject jso = JSON.decode(response.getText());
                        DSResponse ds = new DSResponse(JSOHelper.getAttributeAsJavaScriptObject(jso, "response"));
                        if(ds.getStatus() == 0){
                            Record[] records = ds.getData();
                            Audiencia[] audiencias = new Audiencia[records.length];
                            for(int i=0;i&lt;records.length;i++){
                                audiencias[i] = (Audiencia) records[i].getJsObj();
                            }
                            callback.onSuccess(audiencias);
                        }else{
                            callback.onFailure(new Exception(ds.getAttributeAsString("data")));
                        }
                    }else{
                        callback.onFailure(new Exception(response.getStatusText()));
                    }
                }

                @Override
                public void onError(Request request, Throwable exception) {
                    callback.onFailure(exception);
                }
            });
        } catch (Exception e) {
            callback.onFailure(e);
        }
    }

}
</code></pre><p>

Esto es necesario porque el método JSON.decode) crea el objeto Javascript con propiedades (inicio y fin) de tipo String.

SmartGwt – Actualizar los datos de un registro mediante código

Si tienes un ListGrid enlazado a un DataSource y quieres actualizar un registro mediante código, lo puedes hacer de la siguiente manera

</pre><p>IButton btnEliminar=new IButton("Eliminar");<br /> btnEliminar.addClickHandler(new ClickHandler() {<br /> <br /> @Override<br /> public void onClick(ClickEvent event) {<br /> final ListGridRecord empleado = grdEmpleados.getSelectedRecord();<br /> if(grdEmpleados.getSelectedRecord()!=null){<br /> SC.ask("Baja", "¿Dar de baja al empleado '"+empleado.getAttribute("nombre")+"' ?", new BooleanCallback() {<br /> <br /> @Override<br /> public void execute(Boolean eliminar) {<br /> if(eliminar){<br /> empleado.setAttribute("status", "BAJA");<br /> grdEmpleados.updateData(empleado);<br /> }<br /> }<br /> });<br /> }<br /> }<br /> });</p><pre><br />

En este ejemplo utilizamos un botón para dar de baja a un empleado, actualizando su propiedad status en vez de eliminar el registro.

Fuentes:

Changing the list grid values on runtime.