Two useful pages i found

  1. Some days ago i stumbled with this page: http://twistedoakstudios.com/blog/

    When i was coding in .NET it was quite hard to find good information. Great part of the community have a low level of programming skills. I had to look so many pages, it was stressing.

    I think the problem relies on the UI way to do thing of Microsoft. People tend to forget how things work.

    The articles in that blog are from high level programmers: they don’t only code, but understand how it works. The most interesting part is that they use C# to do advanced things.

  2. The other page i’ll like to suggest is: http://www.blueprintcss.org/

    Awesome css framework. If you live web design, you will find everything you need there.

Backbone.js & Knockout

He tenido mucho trabajo y cosas que hacer, que no he podido escribir.

El año pasado mi jefe me pidió que viera las diversas librerías existentes estilo Backbone.js y Knockout. La idea era ver todas las opciones y tomar la más conveniente.

Para ello me puse a leer y buscar bastante información. Además, aproveche de probar cada una y ver como me sentía.  Para ello primero cree una aplicación en Backbone.js y luego observé que tal sería usar Knockout.

El resultado se los comento acá con el código. Así aprenden un poco y elijen el que más les guste.

Backbone.js

Es muy poderoso y usado por muchas personas, pero tiene una curva de aprendizaje un poco fuerte. Se tiene un modelo, con un montón de cosas que hay que definir. Luego, si se siguen las convenciones, al ser modificado, cambia de una vez las vistas. Acá pueden ver mucho mejor todos los detalles.

Lo ideal para trabajar con  él, es tener servicios web de tipo REST.

Crear la aplicación me quitó una tarde y parte de la mañana.

El html:

<div>
    <fieldset>
        <legend>Person List - Using Backbone</legend>
        <div id="person-container">
            <input type="button" value= "Create New" class="Add" id="btn-create-new-person" />
            <table id="person-list">
                <tr>
                    <th>
                        Name
                    </th>
                    <th>
                        Description
                    </th>
                    <th>
                    </th>
                </tr>
            </table>
        </div>
        <script id='person-template' type='text/template'>
            <td><%=ID%></td> <td><%=FirstName%></td> <td><%=LastName%></td> <td><%=Age%></td>
            <td><input type="button" value="Edit" class="person-edit" /> | <input type="button" value="Details" class="person-detail" /> | <input type="button" value="Delete" class="person-delete" /></td>
       </script>
    </fieldset>
</div>

Javascript:

$(function () {

    // Person Model
    var Person = Backbone.Model.extend({
        urlRoot: '/Person/List/',
        initialize: function () {
            console.log('Person initialize');
        },
        defaults: {
            ID: 0,
            FirstName: 'Unknown',
            LastName: 'Unknown',
            Age : 0
        }
    });

    // Person Collection
    var PersonCollection = Backbone.Collection.extend({
        model: Person,
        url: '/Person/List/'
     });

     // Person View - el returns the template enclosed within a tr
     var PersonView = Backbone.View.extend({
         template: _.template($('#person-template').html()),
         tagName: "tr",
         initialize: function () {
             console.log('PersonView initialize');
             this.model.bind('change', this.render, this);
             this.model.bind('remove', this.unrender, this);
         },
         render: function () {
             console.log('PersonView render');
             $(this.el).html(this.template(this.model.toJSON()));
             return this;
         },
         unrender: function () {
             console.log('PersonView unrender');
             $(this.el).remove();
             return this;
         },
         events: {
             "click .person-edit": 'EditPerson',
             "click .person-delete": 'DeletePerson'
         },
         EditPerson: function () {
             console.log('PersonView EditPerson');
             this.model.set({ FirstName: 'Unknown' });
             var self = this;
             this.model.save(this.model, { success: function () {
                 $("input:button", $(self.el)).button();
             }});
        },
        DeletePerson: function () {
            console.log('PersonView DeletePerson');
            this.model.destroy();
        }
    });

    // Actual App view
    var AppView = Backbone.View.extend({
        initialize: function () {
            console.log('AppView initialize');
            this.collection.bind('add', this.AppendPerson, this);
        },
        el: '#person-container',
        counter: 3,
        events: {
            "click #btn-create-new-person": "AddNewPerson"
        },
        AddNewPerson: function () {
            console.log('AppView AddNewPerson');
            this.counter++;
            var newPerson = new Person({ ID: this.counter, FirstName: 'Unknown ' + this.counter, LastName: 'Damn ' + this.counter, Age: this.counter });
            this.collection.add(newPerson);
            newPerson.save(newPerson, { success: function () {
                $("input:button", "#person-list").button();
            }});
        },
        AppendPerson: function (person) {
            console.log('AppView AppendPerson');
            var personView = new PersonView({ model: person });
            $(this.el).find('table').append(personView.render().el);
        },
        render: function () {
            console.log('AppView render');
            if (this.collection.length > 0) {
                this.collection.each(this.AppendPerson, this);
            }
            $("input:button", "#person-list").button();
        }
    });

    var persons = new PersonCollection();
    var view = new AppView({ collection: persons });

    persons.fetch({ success: function () {
        console.log('Fetch called');
        view.render();
    }});
});

Y en el servidor (en mi caso asp.net MVC 3 con C#):

public class PersonController : Controller
{
    List<Person> Persons = new List<Person> {
        new Person (1, "Federico", "Ponte" , 23),
        new Person (2, "Alejandro", "Drago" , 23),
    };

    // Get Person
    [AcceptVerbs(HttpVerbs.Get)]
    public JsonResult List(int? ID)
    {
        if (ID.HasValue)
        {
            Person PersonResult = Persons.Find(p => p.ID == ID);
            return Json(PersonResult, JsonRequestBehavior.AllowGet);
        }
        return Json(Persons, JsonRequestBehavior.AllowGet);
    }

    // Update Person
    [AcceptVerbs(HttpVerbs.Put)]
    public JsonResult List(int ID, Person UpdatedPerson)
    {
        Person PersonResult = Persons.Find(p => p.ID == ID);
        PersonResult.FirstName = UpdatedPerson.FirstName;
        PersonResult.LastName = UpdatedPerson.LastName;
        PersonResult.Age = UpdatedPerson.Age;
        return Json(PersonResult, JsonRequestBehavior.DenyGet);
    }

    //Add Person
    [AcceptVerbs(HttpVerbs.Post)]
    public JsonResult List(Person CreatePerson)
    {
        Persons.Add(CreatePerson);
        return Json(CreatePerson, JsonRequestBehavior.DenyGet);
    }

    //Delete Person
    [AcceptVerbs(HttpVerbs.Delete)]
    public JsonResult List(int ID)
    {
        Person PersonResult = Persons.Find(p => p.ID == ID);
        Persons.Remove(PersonResult);
        return Json(PersonResult, JsonRequestBehavior.DenyGet);
    }
}
public class Person
{
    public Person(int _ID, string _FirstName, string _LastName, int _Age)
    {
        ID = _ID;
        FirstName = _FirstName;
        LastName = _LastName;
        Age = _Age;
    }

    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
}

Como verán es trabajoso, pero trae sus ventajas: super configurable, sirve para celulares, se tienen los servicios web, etc. Si se quiere escalar, es muy fácil.

Es un poco complicado al comienzo, pero una vez que se entiende y se acostumbra es sencillo.

Knockout

Hace uso del patrón Model-View-View Model. Es muy fácil de aprender y es bastante poderoso. Ya viene con un sistema de templates bastante completo y muchas funciones hechas. Se crea el modelo y basta con modificarlo directamente para que las vistas se actualicen. Tiene buena documentación y no es nada complejo.  Para saber más ingresa aquí.

Un modelo sería:

function PersonModel () {
    var self = this;

    self.ID = ko.observable(0);
    self.FirstName = ko.observable('Unknown');
    self.LastName = ko.observable('Unknown');
    self.Age = ko.observable(0);
}

function PersonCollectionModel () {
    var self = this;

    self.Persons = ko.observableArray()
}

$(function (){
    ko.applyBindings(new PersonCollectionModel());
});

La fastidioso es hacer la funcionalidad: no es tan estructurada. Un ejemplo sería lo siguiente:

function PersonModel () {
    var self = this;

    self.ID = ko.observable(0);
    self.FirstName = ko.observable('Unknown');
    self.LastName = ko.observable('Unknown');
    self.Age = ko.observable(0);

    self.changeAndAlert = function (){
        self.FirstName('Hola');
        self.LastName('Chao');

        alert('Me cambie a ' + self.FirstName() + ' ' + self.LastName());
    }
}
</span></span></span>
<pre><pre><pre><div>
    <fieldset>
        <legend>Person List - Using Knockout</legend>
        <div id="person-container">
            <input type="button" value= "Create New" class="Add" id="btn-create-new-person" />
            <table id="person-list">
                <tr>
                    <th>
                        Name
                    </th>
                    <th>
                        Description
                    </th>
                    <th>
                    </th>
                </tr>
                <!-- ko foreach : persons -->
                    <tr>
                        <td data-bind="text : FirstName"></td>
                        <td data-bind="text : LastName"></td>
                        <td><input type="button" data-bind="click : changeAndAlert" value="ChangeAndAlert" /></td>
                    </tr>
                <!-- /ko -->
            </table>
        </div>
    </fieldset>
</div>

El resto de la funcionalidad implementada en el caso de Backbone.js es sencilla de hacer. Con saber usar bien jQuery o alguna otra librería basta con hacer las llamadas ajax correspondientes y modificar el modelo.

Comparación

Personalmente me gustó mucho Backbone.js. Me sentí más cómodo con él. La forma en que incita a uno a programar da una fácil mantenibilidad y pone de forma sencilla el poder escalar. Es un poco complejo de agarrar al comienzo  pero luego se hace fácil.

En cuanto Knockout es el que más he usado y es bastante sencillo. Se aprende fácilmente y es muy simple.

Ambos son igual de capaces, la decisión es por gusto.

Otras

Hace poco me conseguí me con esta librería patrocinada por Google.

Angular JS