ExtJs ViewModel Bind Field doesn't work on array - arrays

I'm trying to bind (two ways bind) some field of my form with data provided by my view model.
When I bind a simple string, it works perfectly. But when I try to bind a form field to an array field inside my viewmodel, modifications are not considered by the view model.
This is my model
Ext.define('Front.model.User', {
extend : 'Ext.data.Model',
fields : [{
name : 'id',
type : 'int'
}, {
name : 'name',
type : 'string'
}, {
name : 'email',
type : 'string'
}, {
name : 'last_connection',
type : 'date',
dateFormat : 'Y-m-d H:i:s'
}, {
name : 'birth',
type : 'date',
dateFormat : 'Y-m-d H:i:s'
}, {
name : 'schedule',
type : 'auto'
}]
});
This is my ViewModel
Ext.define('Front.view.user.SheetModel', {
extend : 'Ext.app.ViewModel',
alias : 'viewmodel.sheet',
requires : ['Front.model.User'],
data : {
currentUser:null
},
model : 'Front.model.User'
});
This is my Form
Ext.define('Front.view.user.Sheet', {
extend : 'Ext.form.Panel',
requires : ['Front.view.user.SheetController'],
controller : 'sheet',
viewModel : {
type : 'sheet'
},
config : {
currentUser : null
}, {
xtype : 'textfield',
fieldLabel : 'De',
name : 'morningstarttest',
width : 60,
bind : {
value : '{currentUser.schedule.lundi.am.start}'
}
}
});
The bind displays the correct value the first time but doesn't update if I change the value.
The 'schedule' field in a model is an array.
Any ideas how I could solve this problem?

How can your code know which item in the array to bind against? You'd need to do something like:
{currentUser.schedule[0].lundi.am.start}
In order to specify an array index. I can't remember offhand if you can do this, and that's because this just feels like a bad idea. I'd suggest rethinking what you're attempting to do. Rather than have schedule as a field on your model, look into associations.

Related

ExtJS: validitychange - exclude hidden input fields from validity check

I have a form with two input fields 'test1' and 'test2' and one combo box. I want to validate this form, the input fields should be not emtpy. I use therefore the config ' allowBlank: false' and the controller method 'onFormValidityChanged'. This works fine.
Now I hide the input field 'test2' when I change the value in the combo box with the controller method 'onChangeCombo' dynamically. Also, I set config ' allowBlank: true' of input field 'test2'. But my form is not valid when the hidden input field 'test2' is empty.
How can I exclude the hidden input field from the validity check?
I use the ExtJS version 6.6.
Thank you for your hints, Thomas
View:
items : [{
xtype : ' formpanel',
trackResetOnLoad : true,
layout : {
type : 'vbox',
align : 'stretch'
},
items : [
{
xtype : ' textfield',
name : 'test1'
itemId : 'test1',
allowBlank : false,
fieldLabel : 'test1'
},
{
xtype : ' combobox',
name : 'combo',
itemId : 'combo',
store: myStore,
listeners : {
change : 'onChangeCombo'
}
},
{
xtype : ' textfield',
name : 'test2'
itemId : 'test2',
allowBlank : false,
fieldLabel : 'test2'
}],
listeners : {
validitychange : 'onFormValidityChanged'
}
}];
Controller:
onFormValidityChanged : function(form, valid) {
var win, button;
win = form.owner.up('window');
button = win.down('[xtype=button]');
button.setDisabled(!valid);
},
onChangeCombo : function(combobox) {
var win, test2;
win = combobox.up('window');
test2 = win.down('textfield[itemId=test2]');
test2.hide();
test2.allowBlank = true;
}
to turn off the validation, just disable this hidden input.
test2.disable();
I have a suggestion for You too:
use test2.setAllowBlank(true) instead of test2.allowBlank = true
don't use reference like win.down(etc.), check out the ViewController options with reference and lookup method
Norbeq's proposal
test2.disable()
get not provide a solution. I don't know why...
I did not follow the dh117's formBind suggestion.
I solved this problem as follows:
test2 = win('textfield[itemId=test2]');
win.remove(test2);
Thank you for your hints, also for the further hints,
Thomas

How can I use the same ExtJS model proxy with modifications in different ViewModels?

I'm using ExtJS 5 and I'm trying to figure out a way to use a proxy defined in a model in several different ViewModels, adding different extraParams to any specific ViewModel. Here is pared-down code to try to illustrate what I'm trying to do (please forgive any minor errors that don't relate to the question- this is not my actual code). Basically, I have a proxy in the model with some paramsToPath that all ViewModels will want. In a specific ViewModel I want to add some extra params (optional, that may not be added in other ViewModels). This is NOT working- I was hoping that I could use a proxy defined in a model (or store) with modifications added in the ViewModel. I've tried adding some extraParams in the ViewModel with the hope that those extraParams would merge to the proxy defined in the model, but it is not working. Any ideas of how I can accomplish this?
Here is the model:
Ext.define('EmployeeManager.model.Employee', {
extend : 'EmployeeManager.model.Base',
idProperty : 'id',
fields : [ {
name : 'id',
type : 'string'
}, {
name : 'name',
reference : 'string'
} ],
proxy : {
paramsToPaths : [ {
params : [ 'locationId' ],
path : '/location/{0}'
} ]
}
});
Here is the store:
Ext.define('EmployeeManager.store.Employees', {
extend : 'Ext.data.Store',
alias : 'store.employees',
requires : [ 'EmployeeManager.model.Employee' ],
model : 'EmployeeManager.model.Employee'
});
Here is the ViewModel:
Ext.define('DpcManager.view.dpc.copy.EmployeeModel', {
extend : 'Ext.app.ViewModel',
alias : 'viewmodel.employee',
data : {
locationId: null,
employeeName: null
},
stores : {
employeeStore : {
type : 'employees',
remoteFilter : true
proxy: {
type : 'rest',
url : '../employee-services/employee/',
extraParams: {
fields: 'id,personId',
locationId: '{locationId}',
name: '{employeeName}'
}
}
}
}
});

Sencha Touch Vbox

I have below requirement of a page with sencha touch:
A drop down of some options
A question posted by users (length may vary big time)
a text area to display get the answer
Two buttons for submit and ignore
I am using vbox layout. Now the problem is I want the page to be fully scrollable instead of partial scrolls on dataview etc.
How can I achieve it. I have similar requirements for different screens.
Below is the code:
Ext.define('HCMDoctor.view.PFQuestion', {
extend : 'Ext.form.Panel',
xtype : 'PFQuestion',
id : 'pfView',
config : {
layout : {
type : 'vbox',
align : 'stretch'
},
flex : 1,
scrollable : true,
items : [{
xtype : 'container',
html : 'Public Forum Question'
}, {
xtype : 'selectfield',
store : 'CommunityWiseQuestions',
name : 'pfCommId',
id : 'pfCommId',
valueField : 'communityId',
displayField : 'displayFull'
}, {
store : 'PFQuestion',
xtype : 'dataview',
flex : 1,
id : 'pfQuestionHolder',
itemTpl : ['{discussionTitle}<br>{description}',
'<br>Posted in {postedInCommunityName}']
}, {
xtype : 'hiddenfield',
id : 'pfQuestionId',
name : 'pfQuestionId'
}, {
xtype : 'textareafield',
id : 'pfAnswer',
name : 'pfAnswer'
}, {
store : 'PFQuestion',
xtype : 'button',
text : 'Ignore',
id : 'ignorePFQuestion'
}, {
store : 'PFQuestion',
xtype : 'button',
text : 'Submit',
id : 'submitPFQuestion'
}
]
}
});
Thanks
onload of store iterate over records and in every iteration create panel with tpl by passing record data to it and add the panel to its parent. something like this:
var parentPanel = Ext.getCmp("pfView");
for(var i=0; i++; i<records.size){
var mypanel = Ext.create("Ext.Panel", {
data : records[i]
});
parentPanel.add(myPanel);
}

How do I show a value from model association in an ExtJS grid?

I am trying to draw a grid where each line is a stock's performance for a single day. In my data structures, I have a Date, a Stock, and a Stock Price resource. The store attached to my grid is the Stock Price store.
So, to the best of my understanding, my biggest problem is that when the grid cell renderers, I need to already have the value, or I need to have a blocking function to get a value.
When I use the getStore() magic function, I'm told the record doesn't know about it (undefined method). I'm assuming it's 'cause the record doesn't have the same functionality as a standalone model.
I see a few ways out of this:
Customise the grid and/or store so that when a load happens, all the related rows are loaded at the same time.
Create a callback in the renderer, and change the cell value afterwards, but I'm ot exactly sure how to do this. I don't actually want to change the cell value (StockId), just the visible output (Symbol).
Change my API to match my view.
Summing these up: #1 seems like a lot of work for a seemingly simple outcome. I keep trying to use the associations, but I'm finding they're not really useful for anything aside from little things here and there, and certainly not for lots of data. #2 I don't quite know where to begin at the moment; and #3 seems like massive overkill, and will generally ruin my server side as I will mean a few more joins, and more complexity when saving records as well.
So, two part question:
Does anyone know how to load a value from an associated model in a grid?
If not, to pique my curiosity, what sort of things are associations used for in any case where there's lots of data to deal with on screen? Lot's of data seems to be the reason to use Ext vs jQueryUI or some other UI framework, so I'm wondering what the associations are for.
Model - Stock Price
Ext.define('MyApp.model.StockPrice', {
extend : 'Ext.data.Model',
idProperty : 'StockPriceId',
fields : [ {
name : 'StockId',
type : 'int'
}, {
name : 'Open',
type : 'float'
}, {
name : 'Close',
type : 'float'
}, {
name : 'DateId',
type : 'date'
}],
proxy : {
type : 'rest',
url : '/api/stock.price'
},
reader : {
type : 'json'
},
associations : [ {
type : 'hasOne',
model : 'MyApp.model.Date',
primaryKey : 'DateId',
foreignKey: 'DateId'
},{
type : 'hasOne',
model : 'MyApp.model.Stock',
primaryKey : 'StockId',
foreignKey : 'StockId'
} ]
});
Model - Stock
Ext.define('MyApp.model.Stock', {
extend : 'Ext.data.Model',
idProperty : 'StockId',
fields : [ {
name : 'StockId',
type : 'int'
}, {
name : 'Symbol',
type : 'string'
} ],
proxy : {
type : 'rest',
url : '/api/stock'
},
reader : {
type : 'json'
},
associations : [ {
type : 'hasMany',
model : 'MyApp.model.StockPick',
primaryKey : 'StockId',
foreignKey : 'StockId'
}]
});
Model - Date
Ext.define('MyApp.model.Date', {
extend : 'Ext.data.Model',
fields : [ 'DateId', 'Date' ]
});
Store - Stock Price
Ext.define('MyApp.store.StockPrice', {
extend : 'Ext.data.Store',
model : 'MyApp.model.StockPrice',
remoteSort : true,
remoteFilter : true,
pageSize : 5,
autoLoad : true
});
View - Stock Price
Ext.define('MyApp.panel.StockData', {
extend : 'Ext.grid.Panel',
store : 'MyApp.store.StockPrice',
columns : [
{
text : 'Symbol',
flex : 1,
sortable : false,
hideable : false,
dataIndex : 'StockId',
renderer : function(stockId, metadata, stockPriceRecord) {
// What goes in here? PROBLEM POINT
MyApp.model.Stock.load(stockId, function() {
// ... some callback
});
// OR
return stockPriceRecord.getStock().get('Symbol');
}
},
{
text : 'Open',
flex : 1,
dataIndex : 'Open',
renderer : 'usMoney'
},
{
text : 'Close',
flex : 1,
dataIndex : 'Close',
renderer : 'usMoney'
},
{
text : 'Volume',
flex : 1,
dataIndex : 'Volume'
}]
});
Your only real option to display data from an associated model in a grid is to use a custom renderer function on the column. This will not change any values; it will simply render the desired output into the cell.
Now, as for implementing that renderer function: I would start by removing the proxies from the models and instead create stores for each model and allow the stores to manage the proxies -- then, attach the store for Stock as a listener on the store for StockPrice to listen for the datachanged event. When the data of the StockPrice store changes, you should grab every unique referenced Stock id and then tell the Stock store to request a payload of stocks with those ids.
That may mean altering your API a little bit to support a SQL IN(...) behind the scenes, but by leaving the joins to the client side you will put less stress on your server side.
In short, you need to use a little bit of all three ideas you came up with in order to best achieve your goal.

ExtJS: Display model in Ext.grid.property.Grid

I'd like to display the persistent fields (those defined in my model file) in a property grid.
Property Grid:
Ext.define('ATCOM.view.InspectorProperties', {
extend : 'Ext.grid.property.Grid',
alias : 'widget.inspectorProperties',
cls : 'property-grid',
height : 150,
listeners : {
beforerender : function() {
// Rename the first column
var cols = this.getView().getHeaderCt().getGridColumns();
cols[0].setText("Property");
},
beforeedit : function(e) {
// Read-only
return false;
}
},
source : {} // Start with no items
});
I load items like so in a select event (in a controller), where record is our model object and getInfo() is the property grid:
var source = {};
source.id = record.get('id');
source.start = record.get('start');
source.end = record.get('end');
this.getInfo().setSource(source);
Model:
Ext.define('ATCOM.model.Shift', {
extend : 'Ext.data.Model',
fields : [ 'id', {
name : 'start',
type : 'date',
}, {
name : 'end',
type : 'date',
}, 'position', 'controller' ],
hasMany : {
model : 'ATCOM.model.ShiftAlloc',
name : 'allocations'
}
});
Is there a better way to go about this so all non-associative fields (excluding allocations in my case) are automatically sent to the property grid? It might also be possible to read the fields with ATCOM.model.Shift.getFields() and iterate over those checking for persistent:false; to keep the remaining keys, but how do I get the class reference from an instance - as in, how do I get ATCOM.model.Shift from one of its instances so I can call getFields()?
EDIT:
For finding the class name: http://docs.sencha.com/ext-js/4-1/#!/api/Ext.Base-static-method-getName
It may work to say setSource(record.data). I am just playing with this now; it seems to show the right information, though you may lose control over the details of which fields to enable for editing, etc.

Resources