JS MVC Smackdown – 1. Knockout – 2. Ember



JS MVC Smackdown – 1. Knockout – 2. Ember

0 0


js-mvc-presentation

Comparison of js mvc frameworks

On Github ericop / js-mvc-presentation

JS MVC Smackdown

A practical look JS MV* Frameworks: Angular 1.5, Ember, VueJS vs. Knockout (with or without components)

Created by EricOP

Press ESC to see the overall roadmap Press SPACE to progress through each slide

Let the JavaScript MVC "SmackDown" Begin

To Start With we had

- Just ASP.NET w/ MVC -

Knockout

Now to Compare to:

ember

Angular

VueJS

With Components

(more on components later)

This is the site UI the follow code examples implement.

Nothing Fancy: a form calls an API, a checkbox with a conditional if, and a forEach loop on the results

1. Knockout





    
First Name *
Last Name *
Find My Registrations

Hold down Alt and click to zoom in and out on the slide

1. Knockout


Hide Events with Meals


            
        
        
            
        
        
            
        
        
            
        
        
            
        
        
            
        
        
            
        
        
            
        
        
            
            
        
    

1. Knockout

// JS Controller, Component, or ViewModel Bits
var myModel = new function () {
    var self = this;
    self.hideEventsWithMeals = ko.observable(false);
    self.firstName = ko.observable("Eric");
    self.lastName = ko.observable("Johnson");
    self.myEvents = ko.observableArray([]);

    self.addEvent = function (event) {
        self.myEvents.push(
            {
                id: event.Id,
                urlId: '/Admin/Details/' + event.Id,
                name: event.Name,
                description: event.Description,
                location: event.Location,
                date: event.Date,
                startTime: event.StartTime,
                endTime: event.EndTime,
                hasMeal: event.HasMeal,
                mealDescription: event.MealDescription,
                pastDate: new Date(event.Date) < new Date()
            })
        console.log('event=', event);
    }

    self.alert = function () {
        alert("Hello, I'm " + self.firstName() + " " + self.lastName() + ", the stuff!");
    };
    self.findMyEvents = function () {

        var that = self;
        //clear old events
        that.myEvents([]);

        $.ajax({
            url: '@Url.Action("MyEventsAPI", "Home")',
            dataType: 'json',
            method: 'GET',
            async: false,
            data: { firstName: self.firstName(), lastName: self.lastName() },
            success: function (data) {
                var responseData = jQuery.parseJSON(data);

                for (i = 0; i < responseData.length; i++) {
                    //console.log('for loop', i, responseData[i]);
                    that.addEvent(responseData[i]);
                }
            }
        });
    }
};
// Knockout bind needed at end
ko.applyBindings(myModel);
					

2. Ember



First Name * {{input class="form-control text-box single-line" value=firstName placeholder="first"}}
Last Name * {{input class="form-control text-box single-line" value=lastName placeholder="last"}}
Find My Registrations

Hold down Alt and click to zoom in and out on the slide

2. Ember


{{input type="checkbox" name="hideEventsWithMeals" checked=hideEventsWithMeals}} Hide Events with Meals


                {{event.name}}
            
            
                {{event.description}}
            
            
            
                {{event.location}}
            
            
                {{event.hasMeal}}
            
            
                {{event.mealDescription}}
            
            
                {{event.startTime}}
            
            
                {{event.endTime}}
            
            
                
            
        
                {{event.name}}
            
            
                {{event.description}}
            
            
            
                {{event.location}}
            
            
                {{event.hasMeal}}
            
            
                {{event.mealDescription}}
            
            
                {{event.startTime}}
            
            
                {{event.endTime}}
            
            
                
            
        

2. Ember

var myEventsApp = Ember.Application.create({
    rootElement: '#myEvents',
});

myEventsApp.ApplicationController = Ember.Controller.extend({
    firstName: "Eric",
    lastName: "Johnson",
    myEvents: [],
    hideEventsWithMeals: false,
    myEventsWithoutMeals: Ember.computed.filterBy('myEvents', 'hasMeal', false),

    actions: {
        alert: function () {
            alert("Hello, I'm " + this.get('firstName') + " " + this.get('lastName') + ", the stuff!");
        },
        addEvent: function (event) {
            this.myEvents.push(
                {
                    id: event.Id,
                    //urlId: '/Admin/Details/' + event.Id, not needed
                    name: event.Name,
                    description: event.Description,
                    location: event.Location,
                    date: event.Date,
                    startTime: event.StartTime,
                    endTime: event.EndTime,
                    hasMeal: event.HasMeal,
                    mealDescription: event.MealDescription,
                    pastDate: new Date(event.Date) < new Date(),
                    hideThisMealEvent: event.hasMeal && this.get('hideEventsWithMeals')
                })
            console.log('event=', event);
        },
        findMyEvents: function () {

            var that = this;
            //clear old events
            that.set('myEvents', []);

            $.ajax({
                url: '@Url.Action("MyEventsAPI", "Home")',
                dataType: 'json',
                method: 'GET',
                async: false,
                data: { firstName: that.get('firstName'), lastName: that.get('lastName') },
                success: function (data) {
                    var responseData = jQuery.parseJSON(data);

                    for (i = 0; i < responseData.length; i++) {
                        //console.log('for loop', i, responseData[i]);
                        that.send('addEvent', responseData[i]);
                    }
                }
            });
        }
    }
})
					

3. Angular 1.5


First Name *
Last Name *
Find My Registrations

Hold down Alt and click to zoom in and out on the slide

3. Angular 1.5


Hide Events with Meals


            {{event.name}}
        
        
            {{event.description}}
        
        
            {{event.date}}
        
        
            {{event.location}}
        
        
            {{event.hasMeal}}
        
        
            {{event.mealDescription}}
        
        
            {{event.startTime}}
        
        
            {{event.endTime}}
        
        
            
        
    

3. Angular 1.5

// JS Controller, Component, or ViewModel Bits
var myEventsApp = angular.module('myEvents', []);

myEventsApp.controller('MyEventsController', function ($scope, $http) {
    var self = this;

    $scope.firstName = "Eric";
    $scope.lastName = "Johnson";
    $scope.myEvents = [];

    self.alert = function () {
        alert("Hello, I'm " + $scope.firstName + " " + $scope.lastName + ", the stuff!");
    };

    self.addEvent = function (event) {
        $scope.myEvents.push(
            {
                id: event.Id,
                //urlId: '/Admin/Details/' + event.Id, not needed
                name: event.Name,
                description: event.Description,
                location: event.Location,
                date: event.Date,
                startTime: event.StartTime,
                endTime: event.EndTime,
                hasMeal: event.HasMeal,
                mealDescription: event.MealDescription,
                pastDate: new Date(event.Date) < new Date()
            })
        console.log('event=', event);
    }

    self.findMyEvents = function () {

        var that = self;
        //clear old events
        $scope.myEvents = [];

        $http({
            url: '@Url.Action("MyEventsAPI", "Home")',
            responseType: 'json',
            method: 'GET',
            async: false,
            params: { firstName: $scope.firstName, lastName: $scope.lastName }
        }).then(function (response) {
            var responseData = angular.fromJson(response.data);

            for (var i = 0; i < responseData.length; i++) {
                //console.log('for loop', i, responseData[i]);
                that.addEvent(responseData[i]);
            }
        });
    }
});
					

4. Vue.js

First Name *
Last Name *
Find My Registrations

Hold down Alt and click to zoom in and out on the slide

4. Vue.js


Hide Events with Meals


            {{event.name}}
        
        
            {{event.description}}
        
        
            {{event.date}}
        
        
            {{event.location}}
        
        
            {{event.hasMeal}}
        
        
            {{event.mealDescription}}
        
        
            {{event.startTime}}
        
        
            {{event.endTime}}
        
        
            
        
    

4. Vue.js

// JS Controller, Component, or ViewModel Bits
new Vue({
    el: '#myEvents',
    data: {
        hideEventsWithMeals: false,
        firstName: "Eric",
        lastName: "Johnson",
        myEvents: []
    },
    methods: {
        alert: function () {
            alert("Hello, I'm " + this.firstName + " " + this.lastName + ", the stuff!");
        },

        addEvent: function (event) {
            this.myEvents.push(
                {
                    id: event.Id,
                    //urlId: '/Admin/Details/' + event.Id, not needed
                    name: event.Name,
                    description: event.Description,
                    location: event.Location,
                    date: event.Date,
                    startTime: event.StartTime,
                    endTime: event.EndTime,
                    hasMeal: event.HasMeal,
                    mealDescription: event.MealDescription,
                    pastDate: new Date(event.Date) < new Date()
                })
            console.log('event=', event);
        },

        findMyEvents: function () {

            var that = this;
            //clear old events
            that.myEvents = [];

            $.ajax({
                url: '@Url.Action("MyEventsAPI", "Home")',
                dataType: 'json',
                method: 'GET',
                async: false,
                data: { firstName: this.firstName, lastName: this.lastName },
                success: function (data) {
                    var responseData = jQuery.parseJSON(data);

                    for (i = 0; i < responseData.length; i++) {
                        //console.log('for loop', i, responseData[i]);
                        that.addEvent(responseData[i]);
                    }
                }
            });

        }
    }
});
					

What are Components?

What are Components?

  • "A powerful, clean way of organizing your UI code into self-contained, reusable chunks." -KO Docs
  • Self Contained View and (optionally) Controller or ViewModel
  • Optionally receives parameters from its parent, for one way data-binding
  • Can use Custom Elements as DOM place-holders
  • Central idea is making an app composed of several smaller elements, which are easier reason about

5. Knockout with Components



 

First Name *
Last Name *
Find My Registrations

Hold down Alt and click to zoom in and out on the slide

5. Knockout with Components



                
            
            
                
            
            
                
            
            
                
            
            
                
            
            
                
            
            
                
            
            
                
            
            
                
                
            
        

5. Knockout with Components

// JS Controller, Component, or ViewModel Bits
var myModel = new function () {
    var self = this;
    self.firstName = ko.observable("Eric");
    self.lastName = ko.observable("Johnson");
    self.myEvents = ko.observableArray([]);

    self.addEvent = function (event) {
        self.myEvents.push(
            {
                id: event.Id,
                urlId: '/Admin/Details/' + event.Id,
                name: event.Name,
                description: event.Description,
                location: event.Location,
                date: event.Date,
                startTime: event.StartTime,
                endTime: event.EndTime,
                hasMeal: event.HasMeal,
                mealDescription: event.MealDescription
            })
        console.log('event=', event);
    }

    self.alert = function () {
        alert("Hello, I'm " + self.firstName() + " " + self.lastName() + ", the stuff!");
    };
    self.findMyEvents = function () {

        var that = self;
        //clear old events
        that.myEvents([]);

        $.ajax({
            url: '@Url.Action("MyEventsAPI", "Home")',
            dataType: 'json',
            method: 'GET',
            async: false,
            data: { firstName: self.firstName(), lastName: self.lastName() },
            success: function (data) {
                var responseData = jQuery.parseJSON(data);

                for (i = 0; i < responseData.length; i++) {
                    //console.log('for loop', i, responseData[i]);
                    that.addEvent(responseData[i]);
                }
            }
        });
    }
};

var resultsModel = function (params) {
    var self = this;

    self.hideEventsWithMeals = ko.observable(false);
    self.results = params.results;
    // The current item will be passed as the first parameter, so we know which event.id we have
    self.viewDetails = function (event) {
        window.location.replace("/Admin/Details/" + event.id);
    }
}
ko.components.register('results-table', {
    template: { element: 'results-table-template' },
    viewModel: resultsModel
});

var overallViewModel = {
    myModel: myModel,
    resultsModel: new resultsModel(myModel.myEvents)
};

ko.applyBindings(overallViewModel);
					

6. Ember with Components


{{my-events}}
First Name * {{input class="form-control text-box single-line" value=firstName placeholder="first"}}
Last Name * {{input class="form-control text-box single-line" value=lastName placeholder="last"}}
Find My Registrations

Hold down Alt and click to zoom in and out on the slide

6. Ember with Components








  
{{input type="checkbox" name="hideEventsWithMeals" checked=hideEventsWithMeals}} Hide Events with Meals


                {{event.name}}
            
            
                {{event.description}}
            
            
            
                {{event.location}}
            
            
                {{event.hasMeal}}
            
            
                {{event.mealDescription}}
            
            
                {{event.startTime}}
            
            
                {{event.endTime}}
            
            
                
            
        
                {{event.name}}
            
            
                {{event.description}}
            
            
            
                {{event.location}}
            
            
                {{event.hasMeal}}
            
            
                {{event.mealDescription}}
            
            
                {{event.startTime}}
            
            
                {{event.endTime}}
            
            
                
            
        

6. Ember with Components

var myEventsApp = Ember.Application.create({
    rootElement: '#myEvents',
});

myEventsApp.MyEventsComponent = Ember.Component.extend({
    firstName: "Eric",
    lastName: "Johnson",
    myEvents: [],

    actions: {
        alert: function () {
            alert("Hello, I'm " + this.get('firstName') + " " + this.get('lastName') + ", the stuff!");
        },
        addEvent: function (event) {
            this.myEvents.push(
                {
                    id: event.Id,
                    //urlId: '/Admin/Details/' + event.Id, not needed
                    name: event.Name,
                    description: event.Description,
                    location: event.Location,
                    date: event.Date,
                    startTime: event.StartTime,
                    endTime: event.EndTime,
                    hasMeal: event.HasMeal,
                    mealDescription: event.MealDescription,
                    pastDate: new Date(event.Date) < new Date()
                })
            console.log('event=', event);
        },
        findMyEvents: function () {

            var that = this;
            //clear old events
            that.set('myEvents', []);

            $.ajax({
                url: '@Url.Action("MyEventsAPI", "Home")',
                dataType: 'json',
                method: 'GET',
                async: false,
                data: { firstName: that.get('firstName'), lastName: that.get('lastName') },
                success: function (data) {
                    var responseData = jQuery.parseJSON(data);

                    for (i = 0; i < responseData.length; i++) {
                        //console.log('for loop', i, responseData[i]);
                        that.send('addEvent', responseData[i]);
                    }
                }
            });
        }
    }
});

myEventsApp.ResultsTableComponent = Ember.Component.extend({
    ResultsTableComponent: [],
    hideEventsWithMeals: false,
    myEventsWithoutMeals: Ember.computed.filterBy('results', 'hasMeal', false),

    actions: {
        viewDetails: function (eventId) {
            window.location.replace("/Admin/Details/" + eventId);
        }
    }
});
					

Summary :

They're all good MV* Frameworks

Thank you for following along!

*Press B or . on your keyboard to go black screen for a mic-drop. *

JS MVC Smackdown A practical look JS MV* Frameworks: Angular 1.5, Ember, VueJS vs. Knockout (with or without components) Created by EricOP Press ESC to see the overall roadmap Press SPACE to progress through each slide