Results 1 to 6 of 6

Thread: Binding a ViewModel data to fields in a View

  1. #1

    Default Answered: Binding a ViewModel data to fields in a View

    Hi everyone,

    So we've just started with Extjs 6.7 coming from Sencha Touch 2.4.1 and we wanted to use the View - ViewController - ViewModel method. With a bit of prototyping we managed to create an app with a few packages, a login function and a store that loads in data using our application server.

    But now I want to be able to put that data into a few fields so we can edit them and use validations in the fields itself. But I can't really figure out how this is suppose to be done.

    We have the following ViewModel, which has a store 'UserInformation' that uses a other model which contains the fields and validations.
    Code:
    Ext.define('Dashboard.view.dashboard.DashboardModel', {    
        extend: 'Ext.app.ViewModel',
    
        alias: 'viewmodel.dashboard',
    
        requires: [
            'Dashboard.view.dashboard.UserInformation'
        ],
    
        stores: {
            userinformation: {
                autoLoad: true,
                model: 'Dashboard.view.dashboard.UserInformation',
                proxy: {
                    type: 'ajax',
                    noCache: true,
                    url: 'some url that communicates with our application server',
                    headers: { 'Content-Type': 'application/json' },
                    reader: Ext.create('Ext.data.reader.Json', {
                        type: 'json',
                        rootProperty: 'data'                
                    })
                }
            }
        }
    
    });
    What I would like is that when the data is loaded in, it then shows it in some fields of the following view:
    Code:
    Ext.define('Dashboard.view.dashboard.Dashboard', {    extend: 'Ext.Container',
        xtype: 'app-dashboard',
    
        requires: [
        ],
       
    
        config: {
            title: 'Dashboard'
        },
    
    
        controller: 'dashboard',
        viewModel: 'dashboard',
    
        items: [
            {
                xtype: 'panel',
                modelValidation: true,
                items: [{
                    xtype: 'textfield',
                    bind: '{userinformation.user_number}'
                },{
                    xtype: 'textfield',
                    bind: '{userinformation.user_logname}'
                },{
                    xtype: 'textfield',
                    bind: '{userinformation.user_fullname}'
                },{
                    xtype: 'textfield',
                    bind: '{userinformation.user_department}'
                }]
            }
        ]
    });
    
    
    To access the data that is in the model I have to create this long line: this.getViewModel().getData().userinformation.data.items[0]; So I wonder how the View is suppose to know how to get the data and set them into the fields.

    Update: So I found the following Fiddle which roughly does what I'm trying to do:
    https://fiddle.sencha.com/#view/editor&fiddle/2d0a

    Difference being that my store in the ViewModel is loaded after the formula
    setFormData is called and thus the formData in the ViewModel remains null.


  2. I am no expert... but here goes.

    In the view model add a data value that is a single record from the userInformation store. It is the current record being edited.

    In this example I create an eventedConfig for currentUser. When you call panel.setCurrentUser(currentUserRecord) it will set the currentUser in the
    viewmodel and you will have a two way binding. I think the panel should be a formpanel but not sure.

    The idea is that you have to bind single record to the form and fields to each textfield not a store.

    Code:
    Ext.define('Dashboard.view.dashboard.DashboardModel', {    
        extend: 'Ext.app.ViewModel',
    
        alias: 'viewmodel.dashboard',
    
        requires: [
            'Dashboard.view.dashboard.UserInformation'
        ],
    
        data: {
            currentUser: null
        }
    
        stores: {
            userinformation: {
                autoLoad: true,
                model: 'Dashboard.view.dashboard.UserInformation',
                proxy: {
                    type: 'ajax',
                    noCache: true,
                    url: 'some url that communicates with our application server',
                    headers: { 'Content-Type': 'application/json' },
                    reader: Ext.create('Ext.data.reader.Json', {
                        type: 'json',
                        rootProperty: 'data'                
                    })
                }
            }
        }
    
    });
    
    
    Ext.define('Dashboard.view.dashboard.Dashboard', {    extend: 'Ext.Container',
        xtype: 'app-dashboard',
    
        requires: [
        ],
       
    
        config: {
            title: 'Dashboard'
        },
    
    
        controller: 'dashboard',
        viewModel: 'dashboard',
    
        eventedConfig: {
            /**
             * Make the config trigger an event on change to allow the controller to monitor it.
             * https://www.sencha.com/blog/using-sencha-ext-config/
             */
            currentUser: null
        },
    
        listeners: {
           currentUserchange: function (instance, newValue, oldValue) {
                console.log("currentUser CHANGED on form ");
                instance.getViewModel().set("currentUser", newValue);
            }
        },
    
        items: [
            {
                xtype: 'panel',
                modelValidation: true,
                items: [{
                    xtype: 'textfield',
                    bind: '{currentUser.user_number}'
                },{
                    xtype: 'textfield',
                    bind: '{currentUser.user_logname}'
                },{
                    xtype: 'textfield',
                    bind: '{currentUser.user_fullname}'
                },{
                    xtype: 'textfield',
                    bind: '{currentUser.user_department}'
                }]
            }
        ]
    });

  3. #2
    Sencha Premium User evant's Avatar
    Join Date
    Apr 2007
    Location
    Sydney, Australia
    Posts
    19,250
    Answers
    758

    Default

    A store is a collection of records, so saying "userinformation.user_logname" doesn't really make sense. Are you intending to only load a single record?
    Twitter - @evantrimboli
    Former Sencha framework engineer, available for consulting.
    As of 2017-09-22 I am not employed by Sencha, all subsequent posts are my own and do not represent Sencha in any way.

  4. #3

    Default

    Quote Originally Posted by evant View Post
    A store is a collection of records, so saying "userinformation.user_logname" doesn't really make sense. Are you intending to only load a single record?
    In this example; yes

    But in the future if maybe we want to edit a certain record(Say for a CRM app where you edit a relation), we want the fields to be filled with the data of this record and bind them using the viewmodel.

  5. #4
    Sencha User
    Join Date
    Sep 2007
    Location
    Phoenix AZ
    Posts
    118
    Answers
    5

    Default

    I am no expert... but here goes.

    In the view model add a data value that is a single record from the userInformation store. It is the current record being edited.

    In this example I create an eventedConfig for currentUser. When you call panel.setCurrentUser(currentUserRecord) it will set the currentUser in the
    viewmodel and you will have a two way binding. I think the panel should be a formpanel but not sure.

    The idea is that you have to bind single record to the form and fields to each textfield not a store.

    Code:
    Ext.define('Dashboard.view.dashboard.DashboardModel', {    
        extend: 'Ext.app.ViewModel',
    
        alias: 'viewmodel.dashboard',
    
        requires: [
            'Dashboard.view.dashboard.UserInformation'
        ],
    
        data: {
            currentUser: null
        }
    
        stores: {
            userinformation: {
                autoLoad: true,
                model: 'Dashboard.view.dashboard.UserInformation',
                proxy: {
                    type: 'ajax',
                    noCache: true,
                    url: 'some url that communicates with our application server',
                    headers: { 'Content-Type': 'application/json' },
                    reader: Ext.create('Ext.data.reader.Json', {
                        type: 'json',
                        rootProperty: 'data'                
                    })
                }
            }
        }
    
    });
    
    
    Ext.define('Dashboard.view.dashboard.Dashboard', {    extend: 'Ext.Container',
        xtype: 'app-dashboard',
    
        requires: [
        ],
       
    
        config: {
            title: 'Dashboard'
        },
    
    
        controller: 'dashboard',
        viewModel: 'dashboard',
    
        eventedConfig: {
            /**
             * Make the config trigger an event on change to allow the controller to monitor it.
             * https://www.sencha.com/blog/using-sencha-ext-config/
             */
            currentUser: null
        },
    
        listeners: {
           currentUserchange: function (instance, newValue, oldValue) {
                console.log("currentUser CHANGED on form ");
                instance.getViewModel().set("currentUser", newValue);
            }
        },
    
        items: [
            {
                xtype: 'panel',
                modelValidation: true,
                items: [{
                    xtype: 'textfield',
                    bind: '{currentUser.user_number}'
                },{
                    xtype: 'textfield',
                    bind: '{currentUser.user_logname}'
                },{
                    xtype: 'textfield',
                    bind: '{currentUser.user_fullname}'
                },{
                    xtype: 'textfield',
                    bind: '{currentUser.user_department}'
                }]
            }
        ]
    });

  6. #5

    Default

    Quote Originally Posted by mcg1103 View Post
    I am no expert... but here goes.

    In the view model add a data value that is a single record from the userInformation store. It is the current record being edited.

    In this example I create an eventedConfig for currentUser. When you call panel.setCurrentUser(currentUserRecord) it will set the currentUser in the
    viewmodel and you will have a two way binding. I think the panel should be a formpanel but not sure.

    The idea is that you have to bind single record to the form and fields to each textfield not a store.

    Code:
    Ext.define('Dashboard.view.dashboard.DashboardModel', {    
        extend: 'Ext.app.ViewModel',
    
        alias: 'viewmodel.dashboard',
    
        requires: [
            'Dashboard.view.dashboard.UserInformation'
        ],
    
        data: {
            currentUser: null
        }
    
        stores: {
            userinformation: {
                autoLoad: true,
                model: 'Dashboard.view.dashboard.UserInformation',
                proxy: {
                    type: 'ajax',
                    noCache: true,
                    url: 'some url that communicates with our application server',
                    headers: { 'Content-Type': 'application/json' },
                    reader: Ext.create('Ext.data.reader.Json', {
                        type: 'json',
                        rootProperty: 'data'                
                    })
                }
            }
        }
    
    });
    
    
    Ext.define('Dashboard.view.dashboard.Dashboard', {    extend: 'Ext.Container',
        xtype: 'app-dashboard',
    
        requires: [
        ],
       
    
        config: {
            title: 'Dashboard'
        },
    
    
        controller: 'dashboard',
        viewModel: 'dashboard',
    
        eventedConfig: {
            /**
             * Make the config trigger an event on change to allow the controller to monitor it.
             * https://www.sencha.com/blog/using-sencha-ext-config/
             */
            currentUser: null
        },
    
        listeners: {
           currentUserchange: function (instance, newValue, oldValue) {
                console.log("currentUser CHANGED on form ");
                instance.getViewModel().set("currentUser", newValue);
            }
        },
    
        items: [
            {
                xtype: 'panel',
                modelValidation: true,
                items: [{
                    xtype: 'textfield',
                    bind: '{currentUser.user_number}'
                },{
                    xtype: 'textfield',
                    bind: '{currentUser.user_logname}'
                },{
                    xtype: 'textfield',
                    bind: '{currentUser.user_fullname}'
                },{
                    xtype: 'textfield',
                    bind: '{currentUser.user_department}'
                }]
            }
        ]
    });
    Thanks, that actually kinda works for me. A colleague of mine also found another way to do this, using a link in the ViewModel, and in the UserInformation model just a proxy. But then you can only use an ID to get the single record but what if you have some more parameters to use

  7. #6
    Sencha User
    Join Date
    Sep 2007
    Location
    Phoenix AZ
    Posts
    118
    Answers
    5

    Default

    You can use the addFilter() or setFilters() on the store to add other parameters to be passed doing the load.

    If you are just trying to get a single record (instance of a model) From what I understand there are two ways to do this.

    One way is to create an instance of the model and execute the load method. You can pass in params. I am using the Ext.Direct (json RPC like framework) store. Not sure if this has anything to do with the params etc.
    When you define the model you define the api in the proxy that you are using so it knows what methods to call for loading, saving and deleting records.

    Code:
    // this goes in the Model class.
    
      proxy: {
                type: 'direct',
    			// This is for the read method  extraParams are not
    			// sent in any of the other methods as per the Ext.Direct Proxy.
                extraParams: {
                    entityName: '{entityName}'
                },
                api: {
                    prefix: 'GenericDirect',
                    create: 'create',
                    read: 'read',
                    update: 'update',
                    destroy: 'destroy'
                },
                reader: {
                    type: 'json',
                    rootProperty: 'data',
                    totalProperty: 'total',
                    messageProperty: 'message'
                },
    			// This is used by all methods other than read.
    			metadata: {
    				entityName: '{entityName}'
    			}
    
            }




    Code:
    		let header = new Dcs.model.InvoiceHeader();
    		header.load({
    			params: {
    				id: {
    					divisionCode: divcode,
    					invoiceCode: invcode
    				}
    			},
    			failure: function(record, operation) {
    				console.log("failed to load invoice");
    			},
    			success: function(record, operation) {
    				viewModel.set('invoiceHeaderRecord', header);
    				console.log('loaded invoice');
    			},
    			callback: function(record, operatioin, success) {
    				console.log("nvoice callback");
    			}
    		});



    The other way is by sending the primary key or the idProperty field as the first
    argument in the static load method of the model class.



    Code:
    	
    		let header = Dcs.model.InvoiceHeader.load(divcode+":"+invcode, {
    			failure: function(record, operation) {
    				console.log("failed to load invoice");
    			},
    			success: function(record, operation) {
    				viewModel.set('invoiceHeaderRecord', header);
    				console.log('loaded invoice');
    			},
    			callback: function(record, operatioin, success) {
    				console.log("nvoice callback");
    			}
    		});

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •