1
votes

I've been having a little trouble figuring out the best approach for this problem... should I use a form with a loaded record (gives me easy access to validation on each field), or should I let binding do all of the work (can leverage the ViewModel more). I haven't been able to decide, so currently, I'm utilizing both... I'm setting a viewModel record AND loading my form with the same record. I really don't like this approach, but it's getting the job done. That's besides the point of this post... more of a background to why I'm doing this.

Anyway, I'm trying to figure out how I can leverage this form/view model record to determine if a change has happened on a ComboBox. It appears that the form's record does not get updated when you edit a field in a form. I'm assuming that's why updateRecord exists. However, I don't want to have to run updateRecord after every time a field is changed... is there a way to set this up to "bind" to or auto-update the form's record?

Here's an example. I have a grid with two items, a name and their animal type. When the user clicks the edit icon, a window pops up with a form and these two items. The animal type is a combobox, and when the user changes it to Human, I want to show the Human Trait field and hide the Dog Trait field, and vice versa.

I know I can listen to the selection of the combobox and update the view model's record or do the toggling in there, but ideally, I wouldn't have to do any of this if my view model's record was updated from the field's input changes. Does anyone have any guidance or ideas on how to do this? Or maybe how to improve the flow?

Ext.application({
  name: 'Fiddle',

  launch: function() {
    Ext.define('MyModel', {
      extend: 'Ext.data.Model',
      fields: [{
        name: 'name',
        type: 'string'
      }, {
        name: 'animal',
        type: 'string'
      }]
    });
    var store = Ext.create('Ext.data.Store', {
      model: 'MyModel',
      proxy: {
        type: 'memory'
      },
      data: [{
        name: 'Poochie',
        animal: 'Dog'
      }, {
        name: 'Homer',
        animal: 'Human'
      }]
    });
    Ext.define('MyEditWindowViewModel', {
      extend: 'Ext.app.ViewModel',
      alias: 'viewmodel.myeditwindow',
      formulas: {
        hideHumanField: function(getter) {
          var hide = false;
          var currentRecord = getter('currentRecord');
          console.log(currentRecord.getData());
          if (currentRecord.get('animal') === 'Dog') {
            hide = true;
          }
          return hide;
        }
      },
      stores: {
        animalStore: {
          fields: ['name'],
          proxy: {
            type: 'memory'
          },
          data: [{
            name: 'Human'
          }, {
            name: 'Dog'
          }]
        }
      }
    });
    Ext.define('MyEditWindowViewController', {
      extend: 'Ext.app.ViewController',
      alias: 'controller.myeditwindow',
      init: function() {
        var viewModel = this.getViewModel();
        this.getViewForm().loadRecord(viewModel.get('currentRecord'));
      },
      getViewForm: function() {
        return this.lookupReference('myForm');
      }
    });
    Ext.define('MyEditWindow', {
      extend: 'Ext.window.Window',
      controller: 'myeditwindow',
      viewModel: {
        type: 'myeditwindow'
      },
      autoShow: true,
      height: 400,
      width: 400,
      modal: true,
      title: 'Edit Window',
      items: [{
        xtype: 'form',
        reference: 'myForm',
        layout: {
          type: 'vbox'
        },
        items: [{
          xtype: 'textfield',
          name: 'name',
          fieldLabel: 'Name'
        }, {
          xtype: 'combo',
          name: 'animal',
          displayField: 'name',
          valueField: 'name',
          bind: {
            store: '{animalStore}'
          },
          fieldLabel: 'Type'
        }, {
          xtype: 'textfield',
          name: 'humanField',
          hidden: true,
          bind: {
            hidden: '{hideHumanField}'
          },
          fieldLabel: 'Human Trait'
        }, {
          xtype: 'displayfield',
          name: 'dogField',
          hidden: true,
          bind: {
            hidden: '{!hideHumanField}'
          },
          fieldLabel: 'Dog Trait',
          value: 'Cannot set trait'
        }]
      }]
    });
    Ext.create('Ext.grid.Panel', {
      store: store,
      columns: [{
        xtype: 'actioncolumn',
        items: [{
          icon: 'http://icongal.com/gallery/download/93429/256/png',
          tooltip: 'Edit',
          handler: function(grid, rowIndex, colIndex) {
            Ext.create('MyEditWindow', {
              viewModel: {
                data: {
                  currentRecord: grid.getStore().getAt(rowIndex)
                }
              }
            });
          }
        }]
      }, {
        text: 'Name',
        dataIndex: 'name'
      }, {
        text: 'Animal Type',
        dataIndex: 'animal'
      }],
      renderTo: Ext.getBody()
    });
  }
});

I think my question is very similar to this SO question, but the answer does not help, as the phantom property is only checked when the view is first created... not after subsequent changes.

Also found this thread, which I believe is describing the same issue.

1

1 Answers

0
votes

Edit: Okay, just saw that the question is nearly a year old. However, maybe someone will take a little "AHA!" from my answer :-)

I changed your code a little in my fiddle: https://fiddle.sencha.com/#fiddle/19pe

To summarize:

  1. I removed the formular in your viewmodel in favour of a calculated field isHuman in your model.
  2. I added bindings to the currentRecord on all fields, so there's no need to call the loadRecord() method.
  3. I bound the hidden property of the "Trait" fields to the calculated isHuman field of the model.

If you actually need to validate the fields values to show an error in the form, you can also use the model validation. Check out the "Validators" section in the docs: http://docs.sencha.com/extjs/5.1/5.1.2-apidocs/#!/api/Ext.data.Model