Can't we make synchronous calls with Ext.data.Store?
I have a model which I'm loading inside a store. Later I'm binding it to a combobox. This flow works fine.
But when I want to set value of combo for default selection, I get JS error saying no elements inside the store. The reason being, the ajax call to fill the store is made after all the JS is executed. I tried making async property to false, but still no luck!!!
Here is my code snippet:
var store = new Ext.data.Store({
proxy: {
type: 'ajax',
url: '/GetAccounts',
reader: {
type: 'json'
}
},
async: false, //Tried this...no luck
cache: false,
autoLoad: true
});
var simpleCombo = Ext.create('Ext.form.field.ComboBox', {
fieldLabel: 'For ',
renderTo: 'simpleCombo',
displayField: AccountName,
valueField: 'AccountId',
store: store,
queryMode: 'local',
forceSelection: true
});
simpleCombo.setValue(store.getAt(0).get('AccountId')); //JS ERROR AT THIS LINE. No elements in the store
Disable the combo until the store is populated. Don't mess with sync request you will freeze the whole page (or even the browser) until the requests finishes.
I posted something similar at https://stackoverflow.com/a/12918140/1449525, but I took this kind of approach:
Add listeners to your combo box so that when the combo box is actually rendered, it should try to set its value
listeners:{
scope: this,
afterRender: this.selectFirstComboItem
}
then add the method to your this (or wherever you prefer).
selectFirstComboItem: function(combo) {
// This will tell us if the combo box has loaded at least once
if (typeof combo.getStore().lastOptions !== "undefined") {
// Grab the first value from the store
combo.setValue(combo.getStore().first().get(combo.valueField));
}
else {
// When the store loads
combo.getStore().on("load", function(store, items){
// Grab the first item of the newly loaded data
combo.setValue(items[0].get(combo.valueField));
});
}
}
Related
The previous version was incorrect. My apologies.
I'm trying to load a store from the server with some parameters.
onSave: function (cmp) {
var vm = cmp.up('stageform').getViewModel();
vm.set("extraParams", {applicationFormId: 1});
var store = vm.getStore("applicationForms");
console.log(store);
}
vm.getStore("applicationForms"); returns null when the event is fired the first time, after that it returns the actual instance of the store.
Why do I get such a strange behavior? And is this the proper way of loading data from the server?
ViewModel Code:
Ext.define('CPCApplication.view.cases.ApplicationFormModel', {
.....
stores: {
applicationForms: {
model: 'CPCApplication.model.ApplicationForm',
autoLoad: true,
proxy: {
type: 'ajax',
extraParams: '{extraParams}',
autoload: true,
url: ...,
reader: {
type: 'json'
}
},
}
}
});
There is no obvious error in the code you posted. I only not quite sure when you call getStore. That can be important because view model exists only together with its view, binding is asynchronous, etc. Thus, it may be (theoretically) that the store really does not yet exist the first time.
Ideally, prepare a showcase and post it to https://fiddle.sencha.com. Then it would be possible to sort out if it is a problem in your app or in Ext. (Btw, which version?)
I am filtering data from server side proxy :
id: 'projectStore',
model: 'project',
remoteSort: true,
remoteFilter: true,
autoLoad: true,
autoSync: true,
proxy: {
type: 'rest',
url: 'app/projects.php',
reader: {
type: 'json',
root: 'projects'
}
}
this is my filter code :
projectStore.clearFilter();
var comboArray = [
Ext.getCmp('projectCombo').getValue(),
Ext.getCmp('statusCombo').getValue(),
Ext.getCmp('typologyCombo').getValue(),
Ext.getCmp('donorCombo').getValue(),
Ext.getCmp('programCombo').getValue(),
Ext.getCmp('regionCombo').getRawValue(),
Ext.getCmp('cityCombo').getRawValue()
];
if (comboArray[0] != "All" && comboArray[0] != 'default combo value') {
projectStore.filter('PRJ_TYPE', comboArray[0]);
}
if (comboArray[1] != "All" && comboArray[1] != 'default combo value') {
projectStore.filter('PRJ_STATUS', comboArray[1]);
}
... And so on,
when I EXTJS sends request to server, server response is correct and grid is loading filtered data for about 2-3 seconds then it becomes unfiltered again! I need it to be filtered until I will clear filter myself, I have tried many things but couldn't find solution for that. thank you in advance!
These are the symptoms of a race condition.
Since your store is configured as autoLoad, it gets loaded unfilteted when the store is instantiated. Then immediately you filter it. If the store's unfiltered load takes a few seconds longer than the filtered load, you will get what you describe.
The solution is to set autoLoad to false and to load the store manually ( if it doesn't already load automatically when you apply the filter ).
I'm developing an application which is build in ExtJS 4.2.2 with symfony2 backend. Now I have following problem :
Lets say that I have 2 mvc's in my frontend - One for managing users and other for managing their data.
Now when user want to delete row of data I have to set his name in that deleted record so it can be archived and other users would know who made the deletion.
The question is how can I access to currently logged in user data from my DataController.
I've tried this:
This is part of code in my DataController, it's responsible for archiving deleted record
//sel[0] is selected record
//console.log({{ app.user.username }}); //I tought it could work somehow :) but it did not
sel[0].set('deleted_at', new Date()); //setting date of deletion
//get user store
//var usrStore = Ext.getStore('common_user.user_store');
var usrStore = Ext.data.StoreManager.lookup('common_user.user_store')
console.log(usrStore); //in both cases ruterns undefined
//sel[0].set('deleted_by', ); //here i want to save user name in column named "deleted_by"
sel[0].save();
sel[0].commit();
grid.getStore().sync();
grid.getStore().reload(); //reload grid
grid.getStore().remove(sel[0]); //remove from grid
This is how I've configured User store proxy
proxy: {
type: 'rest',
url: Routing.generate('webit_sencha_get',{store: 'common_user.user_store'}),
appendId: false,
batchActions: true,
reader: {
type: 'json',
root: 'data'
},
writer: {
type: 'json',
root: 'data',
encode: true,
writeAllFields: true
}
}
Maybe I should load User grid on init of my data controller ? But still, I don't know how to.
Ext.define('Data.controller', {
extend: Ext.app.Controller,
init: function() {
this.control({
...
'data_grid': {
afterrender: this.onDataGridRender
},
'archive_grid': {
afterrender: this.onDataArchiveGridRender
},
'common_user_grid': {
afterrender: this.onUserGridRender // ????
}
});
},
...
So the question is how can I access (if it's possible) name of currently logged in user from other controller
I'll be thankfull for any guidance.
Problem fixed, I just had to pass parameter to my backend save option and then get current user there
This is my code for combo box inside grid:
{
header: 'FSCS',
dataIndex: 'acntOvrrideTypeCd',
flex: 1,
renderer: function(val, metaData, record, rowIndex, colIndex) {
var id = Ext.id();
var store = new Ext.data.Store({
fields: ['code', 'description'],
data: [{
"code": "",
"description": ""
}, {
"code": "E",
"description": "E"
}, {
"code": "D",
"description": "D"
}, {
"code": "S",
"description": "S"
}]
});
Ext.Function.defer(
(function() {
var cb = Ext.create('Ext.form.ComboBox', {
id: 'acntOvrrideTypeCd-' + rowIndex,
queryMode: 'local',
renderTo: id,
store: store,
forceSelection: true,
triggerAction: 'all',
lazyRender: true,
size: 5,
valueField: 'code',
displayField: 'description',
value: val
//listeners:{
// scope: this,
// 'select': Ext.getCmp('amlFscsForm').controller.amlShow(rowIndex)
//}
});
cb.on(afterrender, function() {
console.log("------- box---" + rowIndex);
Ext.getCmp('amlFscsForm').controller.amlShow(rowIndex);
});
}), 0.25);
console.log("i----------" + id);
return (Ext.String.format('<div id="{0}"></div>', id));
}
}
'afterrender' event is not fired. I need to enable or disable component after its rendered.
Can anyone help?
It's just a typo, afterrender should be in quotes otherwise you will just add the function for undefined event.
cb.on('afterrender',function(){
console.log("------- box---" + rowIndex);
Ext.getCmp('amlFscsForm').controller.amlShow(rowIndex);
});
There are a few problems with your code.
It looks like you're trying to create a combobox in the renderer function of a grid (your code at the top didn't get included in the code block). You're better off using the Ext.grid.plugin.CellEditing plugin instead, which will create a field on demand instead of when the column renders. Plus, every time your grid view refreshes you'll be creating another store and combobox for every row in the grid. Not good for performance, not good for the user experience either.
When calling defer, the duration is in milliseconds, not seconds. Also, you don't need to wrap the function in parenthesis. Just give it the function itself. Like this:
Ext.defer(function(){
// do stuff
}, 25);
Setting lazyRender to true only works if your component is the child of some container that doesn't render all its components immediately (like a tabpanel).
It may be easier to just set the disabled config in the combobox when you create it instead of when you render it, unless you don't have the information available at creation time.
Like nscrob said, when using the on method you need to specify the event as a string. If you use the listeners config (which you have commented out), you can just do:
listeners: {
afterrender: function(){
console.log("------- box---" + rowIndex);
Ext.getCmp('amlFscsForm').controller.amlShow(rowIndex);
},
select: function(){
Ext.getCmp('amlFscsForm').controller.amlShow(rowIndex);
}
}
It's important to note that the scope of these listener functions defaults to the component itself (your combobox) so scope: this is unnecessary. Unless you want the scope to be whatever object is creating this combobox, that is.
The first point is the most important. Look into using the CellEditing (or RowEditing) plugin and I guarantee things will go a lot more smoothly.
I'm trying to learn how to use the EXTJS grids for some simple CRUD operations over a table in a admin app.
I have a simple grid that allows someone to edit users, the store is defined as:
var userDataStore = new Ext.data.Store({
id: 'userDataStore',
autoSave: false,
batch: true,
proxy: new Ext.data.HttpProxy({
api: {
read: '/Admin/Users/All',
create: '/Admin/Users/Save',
update: '/Admin/Users/Save'
}
}),
reader: new Ext.data.JsonReader(
{
root: 'Data',
idProperty: 'ID',
totalProperty: 'total',
successProperty: 'success',
messageProperty: 'message'
}, [
{ name: 'ID', type: 'string', allowBlanks: false },
{ name: 'NT_ID', type: 'string', allowBlank: false },
{ name: 'EMail', type: 'string', allowBlank: false },
{ name: 'Name', type: 'string', allowBlank: false },
{ name: 'Enabled', type: 'bool', allowBlank: false },
{ name: 'CurrentRoleCode', type: 'string', allowBlank: false}]
),
writer: new Ext.data.JsonWriter(
{
encode: false,
writeAllFields: true,
listful: true
})
});
This is bound to a grid, and I am able to load and save users without issue. The save button looks like this:
var saveButton = new Ext.Button({
text: 'Save',
disabled: true,
handler: function() {
userDataStore.save();
pageState.ClearDirty();
saveButton.disable();
}
});
However, when creating a new user, the JSON POST for the user is posted to the same REST service end point as "Update", with the only difference being that no ID value is posted (as one is only set in the store when loading from the server).
This works, and I am able to create users.
The save REST service emits back the created row with the new database ID, and I was under the assumption that EXTJS would automatically bind the new generated database ID to the row. This allows the user to further edit that row, and cause an update instead of a insert.
Instead, the row continues to have a blank user ID, so an additional save creates another new user.
So either:
EXTJS is supposed to resolve generated row ID's automatically and I am just doing something wrong.
I am supposed to manually reload the grid after each save with an additional REST call.
I've been looking at EXTJS documentation and forums, but I am unclear on the proper approach.
Can someone clarify?
EDIT: I tried returning Success = True in JSON to match the SuccessProperty, however this still didn't seem to work.
EDIT #2: So far the only thing I've found that works is doing "userDataStore.reload()" after saving, however because I was returning the contents of the store back after saving, I was hoping that EXTJS would understand that and update the row values.
I've got an idea that may help you. Let't suppose that user added a new
record in grid, in that moment add a new property newRecOrderNo to the record to
identify the record after response. When user will post data to server after
inserting you must get a new ID and associate it to newRecOrderNo
(like Map<Integer,Integer>). Then return json object like that :
{
success : true,
newIdes : {
1 : 23,
2 : 34
}
}
Then when you get response do set proper IDs to records:
userDataStore.each(function(rec){
if(rec.data.newRecOrderNo){
rec.data.ID = response.newIdes[rec.data.newRecOrderNo];
delete rec.data.newRedOrderNo;
}
})
})
Yes, it sets id (and also other fields, if server returns modified values of them), if create ajax backend returns record with set id, at least in extjs 4.1. You should return inserted record, with id set, under 'root' key as json dictionary, in this example root is 'Data', i.e.:
{
"Data": {
"ID": 8932,
"NT_ID": 28738273,
...
"CurrentRoleCode": "aaa",
},
"success": true
}
You need reload store with new params in savebtn handler
like
store.reload();
of course you can add more params to load action