Javascript MVC Learning Note (ii) Controller and status

Source: Internet
Author: User

Today goes into the second part: controller.

Controller and Status

From previous development experience, we have kept the state in the server's session or local cookie, but JavaScript applications are often limited to single pages, so we can also store the state in the client's memory. Saving in memory also means that it can bring a faster interface response.

in MVC, the state is stored in the controller, which is the link between the view and the model in the application. when the page is loaded, the controller binds the event handler to the view and handles the callback at the appropriate time, as well as the necessary docking with the model.

The controller is modular and very independent and ideally should not define any global variables, but should be defined as fully decoupled functional components. So we use the module mode to put the controller in an anonymous function that is immediately processed and pass the global parameters in, to avoid the need to traverse the scope when the global variable is accessed internally, and to clearly illustrate which global variables the module uses.

(function($){var mod = {};Change the context of the parameter and immediately execute mod.load = function(func){        $($.proxy(func, this));};Click event Mod.assetsclick = function(){//Processing click Console.log("click!");}//Call the Load method mod.load(function(){//Add click event for element This.view = $("#view");        This.view.find(". Assets"). Click($.proxy(this. Assetsclick, this)    ); });})(jQuery);

Assume that the following elements are in the page

<div id="view">    <button class="assets">按钮</button></div>

Clicking the button will output "Click", which also implies the connection between the Controller and the view, in fact, this part of the book is about how to save the state in the controller, depending on the state of the different view changes.

(note) Jquery.proxy (method, context)

The $.proxy method is the proxy method in jquery, which receives two parameters and returns a new method that always maintains the context.
For example, in the Monitor of the button:

$("#btn").click(function(){    //这里的this代表按钮});
$("#btn").click(    $.proxy(function(){        //这里的this代表window    }, window););
Abstract out library (end of annotation)

Now abstract the controller into a library and add some new methods so that it can be reused externally or in other modules.

(function($, exports){//If parameters are passed by construction method, the include method is called var mod = function(includes){if(includes){This.include(includes);}    };Change the prototype object name (easy to call) Mod.fn = Mod.prototype;Define your own proxy method, the context always points to the controller itself Mod.fn.proxy = function(func){return $.proxy(func, this);};Execute function mod.fn.load = functions immediately(func){        $(this. Proxy(func));};Adding a method to the constructor mod.fn.include = function(ob){$.extend(This, ob);};The constructor is exposed to the global, and exports can be accessed from outside. Controller = MoD;})(jQuery, window);

When a controller is needed elsewhere, it can be called:

(function($, Controller){//create controller var mod = new Controllers();Change the class name of the view Mod.toggleclass = function(e){The Toggleclass method in//jquery represents the deletion if there is such a name, and if it does not exist, add This.view.toggleClass("over");}//page is finished loading immediately execute Mod.load(function(){//bind page element, add listener This.view = $("#view");        This.view.mouseover(this. Proxy(this. toggleclass));    This.view.mouseout(this. Proxy(this. toggleclass)); });})(jQuery, Controller)

In the above use, the method of immediate invocation through anonymous functions is not loaded after the DOM load, but before the DOM is generated, but the controller's Load method is again after the page document loading is completed before the callback. We can further rewrite the controller and load the controller uniformly after Dom generation.

//Define a Global objectvarExports = This;( function($){    varMoD = {};//Provide a Create method to generate the controllerMod.create = function(includes){        The//create method returns the result, a controller        varresult = function(){            //When creating a controller instance call initialization method             This. init.apply ( This,arguments);        } Result.fn = Result.prototype; Result.fn.init = function(){}; Result.proxy = function(func){            return$.proxy (func, This);        };        Result.fn.proxy = Result.proxy; Result.include = function(ob){$.extend ( This. FN, OB);        }; Result.extend = function(ob){$.extend ( This, OB); };if(includes)        {Result.include (includes); }returnResult    }; Exports. Controller = mod;}) (JQuery);

The Init method must be manually specified when the controller is created, and the Init method adds a listener to the DOM element:

$( function(){    //Create Controller    varToggleview = Controller.create ({init: function(view){             This. View = $ (view); This. View.mouseover ( This. Proxy ( This. Toggleclass)); This. View.mouseout ( This. Proxy ( This. Toggleclass)); }, Toggleclass: function(){             This. View.toggleclass ("Over"); }    });//Create an instance of a controller    NewToggleview ("#view");});

When the instance is created, the Init event is triggered in the constructor, and the view is passed into the controller as instantiated, instead of being written to the controller, we can use the control to the different elements while keeping the code as short as possible.

accessing views

A common pattern is a view that has a controller, the view contains the ID, and the element that uses the view within the Controller uses class, so that there is no conflict with the elements of the other view, such as the element with the ToggleView ID view above, so that the element within the view is accessed using the class name.

function(view){    this.view = $(view);    thisthis.view.find(".form");}

But this means that there will be a lot of selectors in the controller that need to constantly look for the DOM, and we can create a special space in the controller to hold the selector to the variable's mapping table:

elements: {    "form.searchForm""searchForm",    "form input[type=text]""searchInput"}

With such a mapping table, the controller's property names (such as searchform) correspond to the specific elements (the form with the class name Searchform), and they are created when the controller is instantiated:

$( function($){Exports. Searchview = Controller.create ({//The elements in the view use the class name to findElements: {"Input[type=search]":"Searchinput","Form":"Searchform"}, Init: function(Element){            //Get view elements             This. El = $ (Element);//Create attributes based on the mapping table             This. refreshelements ();//Add monitoring for elements, etc.             This. Searchform.submit ( This. Proxy ( This. Search)); },//Event handler functionSearch function(e){Console.log ("Searching", This. Searchinput.val ()); },//The selector used internally, specifying the context as a view element$: function(selector){            return$ (Selector, This. EL); },//Create elements within a viewRefreshelements: function(){             for(varKeyinch  This. elements) {//key is the selector name and the value is the property name                 This[ This. Elements[key]] = This. $ (key); }        }    });//view specified with ID    NewSearchview ("#users");});
State machine

State machine is the abbreviation of "Finite state machine", which is essentially composed of two parts: State and converter. It has only one active state, but it also contains many inactive states. The state converter is called when the active state switches between each other.

For example, there are many views in the application, their display is independent of each other, a view is used to display the contact, a view to edit the contact, the two views must be mutually exclusive relationship, one of the show another must be hidden, this scene is very suitable for the introduction of state machine, because it can ensure that only one is active at a time.

First look at the state machine idea, we construct a state machine:

varStateMachine = function(){}; Statemachine.fn = Statemechine.prototype; StateMachine.fn.bind = function(){    if(! This. O) { This. O = $ ({}); }//Bind custom events     This. o.bind.apply ( This. O,arguments);} StateMachine.fn.trigger = function(){    if(! This. O) { This. O = $ ({}); }//Touch Custom Events     This. o.trigger.apply ( This. O,arguments);} StateMechine.fn.add = function(Controller){    //Bind custom events for state machines     This. Bind ("Change", function(e, current){        if(Controller = = current)        {controller.activate (); }Else{controller.deactivate (); }    });//Create an activation method for the controllerController.active = $.proxy ( function(){         This. Trigger ("Change", controller); }, This);}
(note) Custom events in jquery

The code above focuses on bind and trigger, which makes it easy to implement custom events in jquery using these two methods:

var$obj = $({});$obj.bind("myEvent"function(){    console.log("自定义事件");});$obj.trigger("myEvent"//"自定义事件"

Bind means bind, trigger means trigger, you just need one jquery object, so create an empty object and use $ to wrap it into a jquery object.

(End of note)

The Add () method of this state machine adds the incoming controller to the state list, binds a custom change event to the O in the state machine (adds a binding one), and then creates an active () function. When the controller invokes active (), all the change events are triggered, except that the controller that is called executes the Activate method, and all other controllers execute the Deactivate method:

//Controller 1varCon1 = {activate: function(){Console.log ("Con1 Activate"); }, Deactivate: function(){Console.log ("Con1 Deactivate"); }};//Controller 2varCon2 = {activate: function(){Console.log ("Con2 Activate"); }, Deactivate: function(){Console.log ("Con2 Deactivate"); }};varSM =NewStateMachine (); Sm.add (Con1); Sm.add (Con2); con1.active ();//output "Con1 activate" and "Con2 deactivate"

Of course, it can also be triggered directly through the state machine

sm.trigger("change", con1);

Through the state machine switching state, we can combine the controller to change the view, when the Con1 activated when the display of a view, otherwise hidden; con2 when activated to show another view, otherwise hidden. This allows you to switch between views depending on the state.

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

Javascript MVC Learning Note (ii) Controller and status

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.