Simple Login implementation for Dojo MVC

2019-04-11 00:35发布

Is there any example on how to implement a simple login page/dialog? I have been trying to do it with dojo boilerplate (check my previous questions : Layout implementation for Dojo MVC). So far, I have been able to display my dialog box. But I want to be able to get my data and on click event want to have an alert box for example (with his content).

My view:

<form action="Login" method="post" validate="true" id="loginForm">
  <table width="258">
    &nbsp;
    <tr>
      <td><label>Login</label></td>
      <td><input class="cell" type="text" trim="true" dojoType="dijit.form.TextBox" value="" name="login" id="userId"/></td>
    </tr>
    <tr>
      <td><label>Password</label></td>
      <td><input class="cell" type="password" trim="true" dojoType="dijit.form.TextBox" value="" name="password" id="password"/></td>
    </tr>
    <tr><td colspan="2">&nbsp;</td></tr>
    <tr>
      <td colspan="2" align="center">
      <table border="0" cellspacing="0" cellpadding="0">
          <tr>
            <td align="center" valign="top"><button dojoType="dijit.form.Button" type="submit" id="LoginButton" onClick="connect">Ok</button></td>
            &nbsp;
            <td align="left" valign="top"><button dojoType="dijit.form.Button" type="submit" onclick="document.Login.reset()" id="Cancel">Cancel</button></td>
            &nbsp;
            <td><button dojoType="dijit.form.Button" type="submit" onclick="showDialog();" id="resetPassword"> Show Dialog </button></td>
          </tr>
     </table>
     &nbsp;
     </td>
    </tr>
  </table>
</form>

My Widget module/class

define([
    "dojo/_base/declare",
    "dijit/_Widget",
    "dijit/_TemplatedMixin",
    "dijit/_WidgetsInTemplateMixin",
    "dojo/text!app/views/Login/Login.html",
    "dijit/Dialog",
    "dijit/form/Button",
    "dijit/form/TextBox"
], function(
    declare,
    _Widget,
    _TemplatedMixin, 
    _WidgetsInTemplateMixin,
    template,
    Dialog
){
    return declare([_Widget, _TemplatedMixin, _WidgetsInTemplateMixin, Dialog], {

        templateString: template
    });
});

Now, if you check the HTML the element id LoginButton should call in this case a "connection" function. Which should show (on an alert box) the username and password current input.

Where do I put my function? kind of...

    connect : function(){
    alert("username :" + dom.byId("userId").value() 
+ "  Password: " + dom.byId("password").value());
    }

EDIT: New code

define([
    "dojo/_base/declare",
    "dijit/_Widget",
    "dojo/dom",
    "dijit/_TemplatedMixin",
    "dijit/_WidgetsInTemplateMixin",
    "dojo/text!app/views/Login/Login.html",
    "dijit/Dialog",
    "dijit/form/Button",
    "dijit/form/TextBox"
], function(
    declare,
    dom,
    _Widget,
    _TemplatedMixin, 
    _WidgetsInTemplateMixin,
    template,
    Dialog
){
    return declare("login", [_Widget, _TemplatedMixin, _WidgetsInTemplateMixin, Dialog], {

        templateString: template,

        postCreate: function() {
           this.inherited(arguments);
           // make reference to widget from the node attachment
           this.submitButton = dijit.getEnclosingWidget(this.submitButtonNode);
           // override its onSubmit
           this.submitButton.onClick = function(){
             alert("username :" + dom.byId("userId").value() 
                 + "  Password: " + dom.byId("password").value());
           };
        },
        // and a sample on how to implement widget-in-template stateful get/setter pattern
        // e.g. if submitbutton label should change on some event, call as such:
        // dijit.byId('loginForm').set("submitLabel", "Sendin login, please wait");
        _setSubmitLabelAttr : function(value) {
            return this.submitButton.set("label", value);
        },
        _getSubmitLabelAttr : function() {
            return this.submitButton.get("label");
        },
    });
});

My main.js:

define([ 'dojo/has', 'require', 'dojo/_base/sniff'], function (has, require) {
    var app = {};

    if (has('host-browser')) {

        require([ './views/Login', 'dojo/domReady!' ], function (Login) {
            app.login = new Login().placeAt(document.body);

            app.login.startup();

            // And now…
            app.login.show();
        });
    }
    else {
        console.log('Hello from the server!');
    }
});

3条回答
看我几分像从前
2楼-- · 2019-04-11 01:02

Seing as you template the widget, you would want to make use of the templated widget parse. Taken from http://dojotoolkit.org/documentation/tutorials/1.6/templated/ below describes how to attach an event to a simple domnode.

<div 
  data-dojo-attach-point="focusNode"
  data-dojo-attach-event="ondijitclick:_onClick"
  role="menuitem" tabindex="-1">
    <span data-dojo-attach-point="containerNode"></span>
</div>

Seing as you have widgets in template, make references to your child-widgets and set their properties through these references.

<td align="center" valign="top">
  <button 
     id="LoginButton"  type="submit" 
     dojoType="dijit.form.Button"
     dojoAttachPoint="submitButtonNode">
        Ok
   </button>
</td>

Create a folder so it becomes 'sibling' to dijit/dojox/dojo folders, call it 'app'. And following widget declaration, put in a file called app/widget/MyWidget.js under;

define([
    "dojo/_base/declare",
"dijit/_Widget",
"dijit/_TemplatedMixin",
"dijit/_WidgetsInTemplateMixin",
"dojo/text!app/views/Login/Login.html",
"dijit/Dialog",
"dijit/form/Button",
"dijit/form/TextBox"

], function(
    declare,
 _Widget,
_TemplatedMixin, 
_WidgetsInTemplateMixin,
template,
Dialog

){
    return declare("app.widget.MyWidget", [_Widget, _TemplatedMixin, _WidgetsInTemplateMixin, Dialog], {

        templateString: template
        postCreate: function() {
           this.inherited(arguments);
           // make reference to widget from the node attachment
           this.submitButton = dijit.getEnclosingWidget(dojo.query(".dijitButton")[0], this.domNode);
                 // or simply dijit.byId('LoginButton');
           // override its onSubmit
           this.submitButton.onClick = function(){
             alert("username :" + dom.byId("userId").value() 
                 + "  Password: " + dom.byId("password").value());
           };
        },
        // and a sample on how to implement widget-in-template stateful get/setter pattern
        // e.g. if submitbutton label should change on some event, call as such:
        // dijit.byId('loginForm').set("submitLabel", "Sendin login, please wait");
        _setSubmitLabelAttr : function(value) {
            return this.submitButton.set("label", value);
        },
        _getSubmitLabelAttr : function() {
            return this.submitButton.get("label");
        }
    });
});

And once files are in place, write your html like so:

<head>
   <script src=...dojo...></script>
   <script>
      dojo.require([ 
        "dojo/parser", 
        "app/widget/MyWidget",
        "dojo/domReady!" ] , function(parser) {

          parser.parse();

      });
   </script>
</head>
<body>
   <form dojoType="app.widget.MyWidget"></div>
</body>

This will do following:

  • load the dojotoolkit (dojo/dojo.js)
  • create a namespace called 'app' which has a subspace 'widget'
  • render body (the simple form dom node)
  • call script ondomready, requireing app.widget.MyWidget
  • MyWidget requires the dependencies
  • parser.parse instantiates the <form dojoType="mywidget">
查看更多
爱情/是我丢掉的垃圾
3楼-- · 2019-04-11 01:04

I would like to add my solution: http://jsfiddle.net/phusick/tG8Sg/

It is a bit twisted due to constrains of jsFiddle, but the main principles are the same as I employ in my coding.

First of all, the login process (or any other form processing) is encapsulated inside the dialog and it communicate with the rest of the application thought emitting evens via dojo/Evented. This is how it works:

var loginDialog = new LoginDialog({ controller: loginController});
loginDialog.startup();
loginDialog.show();

loginDialog.on("cancel", function() {
    console.log("Login cancelled.");        
});

loginDialog.on("error", function() { 
    console.log("Login error.");
});

loginDialog.on("success", function() { 
    console.log("Login success.");
    console.log(JSON.stringify(this.form.get("value")));
});

As you can see in the jsFiddle, there are two templates dialog-template and login-form-template which I assemble inside the LoginDialog constructor. The reason is I would normally have also a class wrapping dijit/form/Form to do some magic beyond standard dijit/form/Form validation and data serialization, but since login is simple and it'd be a mess in the single file of jsFiddle, I got rid of it. The advantage of separating a form from a dialog is you can use the same form (i.e. View) together with all the form ad hoc code somewhere else, e.g. in a ContentPane. The form is there just to display and gather data to/from user, it should not directly communicate with Model, i.e. web service, there is a Controller for that purpose:

var LoginController = declare(null, {

    constructor: function(kwArgs) {
        lang.mixin(this, kwArgs);
    },

    login: function(data) {
        // simulate calling web service for authentication
        var def = new Deferred();
        setTimeout(lang.hitch(this, function() {
            def.resolve(data.username == this.username && data.password == this.password);                
        }), 1000);
        return def;
    }
});

Create an instance of LoginController:

// provide username & password in the constructor
// since we do not have web service here to authenticate against    
var loginController = new LoginController({username: "user", password: "user"});

and pass it to LoginDialog constructor as yet seen above:

var loginDialog = new LoginDialog({ controller: loginController});

Finally LoginDialog class:

var LoginDialog = declare([Dialog, Evented], {

    READY: 0,
    BUSY: 1,

    title: "Login Dialog",
    message: "",
    busyLabel: "Working...",

    // Binding property values to DOM nodes in templates
    // see: http://www.enterprisedojo.com/2010/10/02/lessons-in-widgetry-binding-property-values-to-dom-nodes-in-templates/
    attributeMap: lang.delegate(dijit._Widget.prototype.attributeMap, {
        message: {
            node: "messageNode",
            type: "innerHTML"               
        }            
    }),

    constructor: function(/*Object*/ kwArgs) {
        lang.mixin(this, kwArgs);            
        var dialogTemplate = dom.byId("dialog-template").textContent; 
        var formTemplate = dom.byId("login-form-template").textContent;
        var template = lang.replace(dialogTemplate, {
            form: formTemplate                
        });

        var contentWidget = new (declare(
            [_Widget, _TemplatedMixin, _WidgetsInTemplateMixin],
            {
                templateString: template                   
            }
        )); 
        contentWidget.startup();
        var content = this.content = contentWidget;
        this.form = content.form;
        // shortcuts
        this.submitButton = content.submitButton;
        this.cancelButton = content.cancelButton;
        this.messageNode = content.messageNode;
    },

    postCreate: function() {
        this.inherited(arguments);

        this.readyState= this.READY;
        this.okLabel = this.submitButton.get("label");

        this.connect(this.submitButton, "onClick", "onSubmit");
        this.connect(this.cancelButton, "onClick", "onCancel");

        this.watch("readyState", lang.hitch(this, "_onReadyStateChange"));

        this.form.watch("state", lang.hitch(this, "_onValidStateChange"));
        this._onValidStateChange();
    },

    onSubmit: function() {
        this.set("readyState", this.BUSY);
        this.set("message", ""); 
        var data = this.form.get("value");

        // ask the controller to login
        var auth = this.controller.login(data);

        Deferred.when(auth, lang.hitch(this, function(loginSuccess) {
            if (loginSuccess === true) {
                this.onLoginSuccess();
                return;                    
            }
            this.onLoginError();
        }));
    },

    onLoginSuccess: function() {
        this.set("readyState", this.READY);            
        this.emit("success");
    },

    onLoginError: function() {
        this.set("readyState", this.READY);
        this.set("message", "Please try again."); 
        this.emit("error");         
    },

    onCancel: function() {
       this.emit("cancel");     
    },

    _onValidStateChange: function() {
        this.submitButton.set("disabled", !!this.form.get("state").length);
    },

    _onReadyStateChange: function() {
        var isBusy = this.get("readyState") == this.BUSY;
        this.submitButton.set("label", isBusy ? this.busyLabel : this.okLabel);
        this.submitButton.set("disabled", isBusy);
    }            
});

Please see templates at the aforementioned jsFiddle. They should be in separate files required via dojo/text! normally. I put them into <script type="text/template"> to fit into jsFiddle.

查看更多
Root(大扎)
4楼-- · 2019-04-11 01:04

With the help of mschr. I came accross this particular solution.

define([
"dojo/_base/declare",
"dojo/dom",
"dijit/_Widget",
"dijit/_TemplatedMixin",
"dijit/_WidgetsInTemplateMixin",
"dojo/text!app/views/Login/Login.html",
"dijit/Dialog",
"dijit/form/Button",
"dijit/form/TextBox"

], function(
    declare,
    dom,
 _Widget,
_TemplatedMixin, 
_WidgetsInTemplateMixin,
template,
Dialog
){
    return declare([_Widget, _TemplatedMixin, _WidgetsInTemplateMixin, Dialog], {

        templateString: template,

        postCreate: function() {
           this.inherited(arguments);
           // make reference to widget from the node attachment
           //this.submitButton = this.getChildren()[ButtonIndex];
           // override its onSubmit
             /*alert("username :" + dom.byId("userId").value() 
                 + "  Password: " + dom.byId("password").value());*/
            dojo.connect(this.loginButton, 'onclick', this._login);
        },
        // and a sample on how to implement widget-in-template stateful get/setter pattern
        // e.g. if submitbutton label should change on some event, call as such:
        // dijit.byId('loginForm').set("submitLabel", "Sendin login, please wait");
        _login : function() {
            var value = dom.byId("userId").value;

            if(value)
                alert("username: " + value);
        },
        // and a sample on how to implement widget-in-template stateful get/setter pattern
        // e.g. if submitbutton label should change on some event, call as such:
        // dijit.byId('loginForm').set("submitLabel", "Sendin login, please wait");
        _setSubmitLabelAttr : function(value) {
            return this.submitButton.set("label", value);
        },
        _getSubmitLabelAttr : function() {
            return this.submitButton.get("label");
        },
    });
});
查看更多
登录 后发表回答