another technical blog...technically

Monday, April 30, 2018

Just another out-of-date but maybe useful trick with KnockoutJS

I know what you're thinking about: another post on KnockoutJS? Again?
To be extremely clear, i 've written this post a lot of months ago but i never completed and published, and really i could not just delete it.

So today i will show you just a little example of comunicating widgets: it's not something complicated, but i think it can be also reproduced in other JS framwork.
Basically, let's assume we have a HTML which contains 2 widgets, the first one is auto-consistent and reusable, while the second one depends on the previous (to be honest this is a derivation from the real world example, when i have 4 widget comunicating one with each other but...).

So we have the code of the first controller, which is the child one.
window.Dummy = window.Dummy || {};
window.Dummy.Custom = window.Dummy.Custom || {};
window.Dummy.Custom.View = window.Dummy.Custom.View || {};
window.Dummy.Custom.View._Child = window.Dummy.Custom.View._Child || {};

(function (controller, utility, api, $, ko) {
    // View model definition
    controller.ViewModel = function viewModel() {
        var vm = this;
        vm.Items = ko.observableArray();

        // Search in all view model items
        vm.Get = function (id) {
            //identify the first matching item by name
            vm.firstMatch = ko.computed(function () {
                var search = id.toLowerCase();
                if (!search) {
                    return null;
                } else {
                    return ko.utils.arrayFirst(vm.Items(), function (item) {
                        return ko.utils.stringStartsWith(item.Id, search);
                    });
                }
            }, vm);

            return vm.firstMatch();
        };

 ...
    };

    // Controller definition
    controller.Loaded = ko.observable(false);
    controller.LoadData = function (data) {
        controller.Vm.Items.push.apply(controller.Vm.Items.sort(), data);

        ...
    };
    controller.Vm = new controller.ViewModel();
    controller.Wrapper = document.getElementById("workout-definitions");

    // Controller initialization
    controller.Init = function () {
        ko.applyBindings(controller.Vm, controller.Wrapper);
        api.GetAll(controller.LoadData);
    };

}(window.Dummy.Custom.View._Child = window.Dummy.Custom.View._Child || {},
    Dummy.Custom.Utility,
    Dummy.Custom.Api._ChildItems,
    jQuery,
    ko));

The controller is capable of calling the API exposed for the objects of this widget so it's possible somelike indipendent from the context. The instance of the view model exposes the Get Method, which searches into the array of objects loaded from API and return a single object.
Here there is instead the code of the parent widget:

window.Dummy = window.Dummy || {};
window.Dummy.Custom = window.Dummy.Custom || {};
window.Dummy.Custom.View = window.Dummy.Custom.View || {};
window.Dummy.Custom.View.Parent = window.Dummy.Custom.View.Parent || {};

(function (controller, 
 utility, 
 $, 
 ko,
    parentApi,
 childView) {

    // View model definition
    controller.ViewModel = function viewModel() {
        var vm = this;
  ...
    };

    // Controller definition
    ...

    // Controller init
    controller.Vm = new controller.ViewModel();
    controller.Init = function (data) {
        controller.LoadUserData(data);

        // Await widgets readyness and then fire method  
        // Load events if athlete is new
        childView.Loaded.subscribe(function (newValue) {
            if (newValue === true) {
    ...
            }
        });
    };
 
    ...
}(window.Dummy.Custom.View.Parent = window.Dummy.Custom.View.Parent || {},
    Dummy.Custom.Utility,
    jQuery,
    ko,
    Dummy.Custom.Api.ParentItems,
    Dummy.Custom.View._Child,
));

As you can imagine i dropped most of the code just to show you the concept. The parent widget is dependant of Child controller, which could be started calling Child.controller.Init everywhere (maybe on document loaded event), the parent is only subscribed to the Child.Loaded variable.
This means that, when the child finished to load data, Parent is triggered to do something else, and this could be someway useful.
It's clear you can use the model with more than one widget, with more than one triggered event, and you have to take care about the data you load, because you will use every widget as a item container, rather than just a graphical item.
Hope you find it useful even if outdated, but i preferred to share this blog post because maybe you can replicate the model using other JS frameworks that support the event subscription technique.
Share:
written in: Milano MI, Italia

0 commenti:

Post a Comment

Because of a lot of SPAM about courses, I need to moderate all comments here.
I ensure you that I will answer whenever possible (if you are not a spammer).

Me, myself and I

My Photo
I'm just another IT guy sharing his knowledge with all of you out there.
Wanna know more?