I have a property grid :
periods.each(function(record){
var tempPropGrid = me.getView().add(
{
xtype:'propertygrid',
width: 80,
header: false,
title: 'prop grid',
//for some reason the headers are not hiding, we may need to deal with this using CSS
//hideHeaders: true,
enableColumnResize: false,
sortableColumns: false,
nameColumnWidth: 1,
source: record.data,
sourceConfig: {
periodScrumMaster: {
editor: Ext.create('Ext.form.ComboBox', {
tdCls: 'red',
store: team,
queryMode: 'local',
displayField: 'personName',
valueField: 'personName',
listeners: {
'expand' : function(combo) {
var gridvalues = this.up('propertygrid').getSource();
combo.getStore().clearFilter(true);
combo.getStore().addFilter({property: 'teamName', value: teamName});
combo.getStore().addFilter({property: 'periodName', value: gridvalues.periodName});
var totalFTE = team.count();
console.log(totalFTE);
var teamStore = Ext.getStore('personPeriods');
console.log('store');
console.log(teamStore);
},
}}),
displayName: 'Scrum Master'
},
},
That has a render listener:
beforerender: function(){
debugger;
var gridValues = this.getSource();
// console.log(record);
//debugger;
// filter periods for this period only
periods.filterBy(function(record,id){
if(record.get("periodName") === gridValues.periodName){
return true;
}});
// filter teamMembers for this period and team
var view = this.up();
var vm = view.getViewModel();
var store = vm.getStore('teamMembers');
store.filterBy(function(record,id){
if(record.get("periodName") === gridValues.periodName) {
return true;
}});
//store.clearFilter(true);
store.addFilter({property: 'teamName', value: teamName});
// get FTEs assigned to this team in this period by counting records
var resourcedFtes = store.count();
// Here I check the record in the periods store to make sure the data matches up with how many resourcedFte there is an update it if required
// This is super bad and will need to refactor
periods.each(function(record,idx){
var value = record.get('resourcedFte');
if(value != resourcedFtes){
record.set('resourcedFte',resourcedFtes);
record.commit();
vm.data.parentController.saveParent();
}});
// Need to call save parent so that the record is updated when we update it above
//Clear everything so that we can start fresh next period
store.clearFilter(true);
//periods.clearFilter(true);
Basically there is some logic to check if the data is correct/up to date and if its not it updates it. This works fine, but the data is not then loaded into the grid. I have to refresh after rendering the grid for it to load correctly.
Is there a way I can call a refresh or reload method on the property grid to load the data again inside an if statement?
If I understand your question, I would suggest you to programm the store proxy so that it returns the whole changed record.
Is your store parametered with autoLoad enabled?
(sorry I can't (yet) comment)
Related
I have a web application with multiple Selectize objects initialized on the page. I'm trying to have each instance load a default value based on the query string when the page loads, where ?<obj.name>=<KeywordID>. All URL parameters have already been serialized are are a dictionary call that.urlParams.
I know there are other ways to initializing Selectize with a default value I could try; but, I'm curious why calling setValue inside onInitialize isn't working for me because I'm getting any error messages when I run this code.
I'm bundling all this JavaScript with Browserify, but I don't think that's contributing to this problem.
In terms of debugging, I've tried logging this to the console inside onInititalize and found that setValue is up one level in the Function.prototype property, the options property is full of data from load, the key for those objects inside options corresponds to the KeywordID. But when I log getValue(val) to the console, I get an empty string. Is there a way to make this work or am I ignoring something about Selectize or JavaScript?
module.exports = function() {
var that = this;
...
this.selectize = $(this).container.selectize({
valueField: 'KeywordID', // an integer value
create: false,
labelField: 'Name',
searchField: 'Name',
preload: true,
allowEmptyOptions: true,
closeAfterSelect: true,
maxItems: 1,
render: {
option: function(item) {
return that.template(item);
},
},
onInitialize: function() {
var val = parseInt(that.urlParams[that.name], 10); // e.g. 5
this.setValue(val);
},
load: function(query, callback) {
$.ajax({
url: that.url,
type: 'GET',
error: callback,
success: callback
})
}
});
};
...
After sprinkling in some console.logs into Selectize.js, I found that the ajax data hadn't been imported, when the initialize event was triggered. I ended up finding a solution using jQuery.when() to make setValue fire after the data had been loaded, but I still wish I could find a one-function-does-one-thing solution.
module.exports = function() {
var that = this;
...
this.selectize = $(this).container.selectize({
valueField: 'KeywordID', // an integer value
create: false,
labelField: 'Name',
searchField: 'Name',
preload: true,
allowEmptyOptions: true,
closeAfterSelect: true,
maxItems: 1,
render: {
option: function(item) {
return that.template(item);
},
},
load: function(query, callback) {
var self = this;
$.when( $.ajax({
url: that.url,
type: 'GET',
error: callback,
success: callback
}) ).then(function() {
var val = parseInt(that.urlParams[that.name], 10); // e.g. 5
self.setValue(val);
});
}
});
};
...
You just need to add the option before setting it as the value, as this line in addItem will be checking for it:
if (!self.options.hasOwnProperty(value)) return;
inside onInitialize you would do:
var val = that.urlParams[that.name]; //It might work with parseInt, I haven't used integers in selectize options though, only strings.
var opt = {id:val, text:val};
self.addOption(opt);
self.setValue(opt.id);
Instead of using onInitialize you could add a load trigger to the selectize. This will fire after the load has finished and will execute setValue() as expected.
var $select = $(this).container.selectize({
// ...
load: function(query, callback) {
// ...
}
});
var selectize = $select[0].selectize;
selectize.on('load', function(options) {
// ...
selectize.setValue(val);
});
Note that for this you first have to get the selectize instanze ($select[0].selectize).
in my case it need refresh i just added another command beside it
$select[0].selectize.setValue(opt);
i added this
$select[0].selectize.options[opt].selected = true;
and changes applied
but i dont know why?
You can initialize each selectize' selected value by setting the items property. Fetch the value from your querystring then add it as an item of the items property value:
const selectedValue = getQueryStringValue('name') //set your query string value here
$('#sel').selectize({
valueField: 'id',
labelField: 'title',
preload: true,
options: [
{ id: 0, title: 'Item 1' },
{ id: 1, title: 'Item 2' },
],
items: [ selectedValue ],
});
Since it accepts array, you can set multiple selected items
I want to update the combobox store whenever there is a change in the combobox and display this changed store. My store is loading but combobox won't display it. I can display local store like I want to display but can't do the same for remote json store.
I have a "ProcessController" like this:
onComboboxChange: function(combo, newValue, oldValue) {
var upContainer = combo.up('container');
if(combo.itemId == "cmbServiceList") {
MyApp.app.globals.cmbServiceStore = this.createServiceCmbStore(upContainer.getComponent('cmbServiceList').getRawValue());
}
},
createServiceCmbStore: function(inputData){
var data = {"inputData": inputData};
var mainController = MyApp.app.getController('MainController');
var cmbServiceData = mainController.callService(data,'getServices','json');
var classServices = Ext.JSON.decode(cmbServiceData);
var projectStore = Ext.create('Ext.data.Store', {
fields: ['key', 'text'],
data: classServices
});
return projectStore;
}
init: function(application) {
this.control({
'combobox': {
change: this.onComboboxChange
}
});
_myAppGlobal = this;
},
And it's my combobox in the main viewport:
{
xtype : 'combobox',
anchor : '80%',
listConfig : {
loadingText : 'Searching...',
emptyText : 'No matching posts found.'
},
typeAhead : true,
itemId : 'cmbServiceList',
fieldLabel : 'Servis Adı:',
hideTrigger : true,
displayField : 'text',
store : MyApp.app.globals.cmbServiceStore,
valueField : 'key',
minChars : 1,
queryMode : 'local',
forceSelection: true
}
MyApp.app.globals.cmbServiceStore is a global variable defined in the app.js
When I debug the code I can see the store is loaded but it won't display any stored value in the combobox.
The issue mainly here is, when your combobox is created the MyApp.app.globals.cmbServiceStore is null or undefined, once the combobox is initialized and then you try to define your store it doesn't the combobox as the reference given during initialization to combobox was undefined.
Based on your code it seems that you are just changing the data of the store and not the store fields. So its much better you create the store before combobox initialization and then on combox change you just add the data to store by using store.add
I would recommend another approach, that is add a proxy to your store for the service and just do store.load() on combo change
if(combo.itemId == "cmbServiceList") {
MyApp.app.globals.cmbServiceStore = this.createServiceCmbStore(upContainer.getComponent('cmbServiceList').getRawValue());
upContainer.getComponent('cmbServiceList').bindStore(MyApp.app.globals.cmbServiceStore);
}
instead of
if(combo.itemId == "cmbServiceList") {
MyApp.app.globals.cmbServiceStore = this.createServiceCmbStore(upContainer.getComponent('cmbServiceList').getRawValue());
}
solved the issue.
I am running a weird problem when I try to set Grid Filter list dynamically.
Let me explain by my code snippets
I have a column with filter list is defined as
{
text : 'Client',
dataIndex : 'topAccount',
itemId : 'exTopAccount',
filter: {
type: 'list',
options:[]
}
}
I initialize list from store in 'viewready'
viewready: function(cmp,eOpts){
cmp.getHeaderCt().child('#exTopAccount').initialConfig.filter.options = clientsStore.collect('topAccount');
}
===> WORKS GOOD
Now, I have to build the new client store based on the records when user moves to next page. Therefore I build the store in the 'change' event of paging
listeners: {
'change' :function( toolbar, pageData, eOpts ) {
var store = Ext.StoreManager.get('ExceptionRecords');
clientsStore.removeAll(true);
store.each(function(record){
if(clientsStore.findRecord('topAccount',record.data.topAccount.trim()) == null ) {
clientsStore.add({topAccount: record.data.topAccount.trim()})
}
})
Ext.getCmp('exceptionGridContainer').view.refresh;
Ext.getCmp('exceptionGridContainer').view.getHeaderCt().doLayout;
console.log(clientsStore);
Ext.getCmp('exceptionGridContainer').view.getHeaderCt().child('#exTopAccount').initialConfig.filter.options = clientsStore.collect('topAccount');
}
}
I can now see the new data in clientsStore . But Grid filter list is not updated. still showing old data. I tried refresh,layout etc. Nothing helps
Any help will be appreciated
Thanks
Tharahan
Just changing the value of a property does not affect the component rendered or computed state. The menu is created when the list is first initialized. The first time you do that, it works because that's before the initialization, but the second time, that's too late.
If you can grab a reference to the instantiated ListFilter, I think you could force the recreation of the menu this way:
listFilter.menu = listFilter.createMenu({
options: [ ... ] // new options
// rest of the filter config
});
So, supposing you have a reference to your target grid, you could change the options for the column with dataIndex of "topAccount" by a call similar to this:
var listFilter = grid
.findFeature('filters') // access filters feature of the grid
.get('topAccount'); // access the filter for column
listFilter.menu = listFilter.createMenu({
options: [ ... ] // new options
// rest of the filter config
});
--- Edit ---
OK, complete example. Tested, working.
Ext.widget('grid', {
renderTo: Ext.getBody()
,height: 400
,features: [{
ftype: 'filters'
,local: true
}]
,columns: [{
dataIndex: 'a'
,text: 'Column A'
,filter: {
type: 'list'
,options: ['Foo', 'Bar']
}
},{
dataIndex: 'b'
,text: 'Column B'
},{
dataIndex: 'c'
,text: 'Column C'
}]
,store: {
fields: ['a', 'b', 'c']
,autoLoad: true
,proxy: {
type: 'memory'
,reader: 'array'
,data: [
['Foo', 1, 'Bar']
,['Bar', 2, 'Baz']
,['Baz', 1, 'Bar']
,['Bat', 2, 'Baz']
]
}
}
,tbar: [{
text: 'Change list options'
,handler: function() {
var grid = this.up('grid'),
// forget about getFeature, I read the doc and found something!
filterFeature = grid.filters,
colAFilter = filterFeature.getFilter('a');
// If the filter has never been used, it won't be available
if (!colAFilter) {
// someone commented that this is the way to initialize filter
filterFeature.view.headerCt.getMenu();
colAFilter = filterFeature.getFilter('a');
}
// ok, we've got the ref, now let's try to recreate the menu
colAFilter.menu = colAFilter.createMenu({
options: ['Baz', 'Bat']
});
}
}]
});
I was solving similar problem and answers to this question helped me a lot. Local List filter menu is in fact lazy loaded (only created when clicked) and I needed to set filter menu to be reloaded if the grid store has been reloaded with different data. Solved it by destroying of menu after each reload, so on next click menu is recreated:
var on_load = function() {
var grid_header = me.gridPanel.filters.view.headerCt
if (grid_header.menu) {
grid_header.menu.destroy();
grid_header.menu = null;
}
}
The following code is working. The problem is the request is being sent with &_dc=1299207914646&limit=25 appended to every request sent to the server. Nothing I can do changes the limit=25. Ideally I want no additional parameters sent to the server. I would make do however with being able to set the limit to 10000 or something. I AM able to add other parameters but nothing I do removes the limit=25. I would also like to get rid of the &_dc parameter although I don't know why it has been added it is not causing a problem.
Any ideas?
note: some weird problem with code formatting below?
Thanks
Ext.require([
'Ext.grid.*',
'Ext.data.*',
'Ext.panel.*'
]);
Ext.onReady(function(){
Ext.regModel('Image_', { // window.Image is protected in ie6 !!!
fields: ['id', 'key', 'value']
});
var store = new Ext.data.JsonStore({
model: 'Image_',
proxy: {
type: 'ajax',
var store = new Ext.data.JsonStore({
model: 'Image_',
proxy: {
type: 'ajax',
autoload: 'false',
url: '/couchdb/test/_design/blah/_view/by_surname2?startkey=%22r%22&endkey=%22r\u9999%22',
reader: {
type: 'json',
root: 'rows'
}
}
});
store.load();
var listView = new Ext.grid.GridPanel({
width:425,
height:250,
collapsible:true,
title:'Simple ListView <i>(0 items selected)</i>',
renderTo: Ext.getBody(),
store: store,
multiSelect: true,
viewConfig: {
emptyText: 'No images to display'
},
headers: [{
text: 'File',
flex: 50,
dataIndex: 'value'
},{
text: 'Last Modified',
flex: 35,
dataIndex: 'key'
},{
text: 'Size',
dataIndex: 'id',
flex: 15,
cls: 'listview-filesize'
}]
});
// little bit of feedback
listView.on('selectionchange', function(view, nodes){
var l = nodes.length;
var s = l != 1 ? 's' : '';
listView.setTitle('Simple ListView <i>('+l+' item'+s+' selected)</i>');
});
});
In your Proxy, set
limitParam: undefined,
pageParam: undefined,
startParam: undefined,
noCache: false,
You can modify your store limit when you load the store.
store.load({params:{limit:50}});
In this case, I am asking to set the limit to 50.
_dc=1299207914646 is unique cache-buster param added to GET requests. If you don't want to have them in the url, you can disable them by setting disableCaching parameter to false.
But I would recommend you to set the method of you store to POST and pass the parameters using POST rather than GET method. That way you can have clean URLs and also hide the data being sent.
You can override getParams method of the Ext.data.proxy.Server.
For example, in my project I added custom boolean parameter embeddedParams and if I dont want to add ExtJS parameters to a request I set it to false in a store proxy:
/**
* Added embeddedParams option
*/
Ext.define('Ext.lib.overrides.ServerProxy', {
override: 'Ext.data.proxy.Server',
/**
* Add or not pagination, grouping, sorting and filtering parameters to the request. Defaults to true.
*/
embeddedParams: true,
/**
* #private
* Copy any sorters, filters etc into the params so they can be sent over the wire
*/
getParams: function (operation) {
var me = this,
params = {},
isDef = Ext.isDefined,
groupers = operation.groupers,
sorters = operation.sorters,
filters = operation.filters,
page = operation.page,
start = operation.start,
limit = operation.limit,
simpleSortMode = me.simpleSortMode,
simpleGroupMode = me.simpleGroupMode,
pageParam = me.pageParam,
startParam = me.startParam,
limitParam = me.limitParam,
groupParam = me.groupParam,
groupDirectionParam = me.groupDirectionParam,
sortParam = me.sortParam,
filterParam = me.filterParam,
directionParam = me.directionParam,
hasGroups, index;
if (me.embeddedParams && pageParam && isDef(page)) {
params[pageParam] = page;
}
if (me.embeddedParams && startParam && isDef(start)) {
params[startParam] = start;
}
if (me.embeddedParams && limitParam && isDef(limit)) {
params[limitParam] = limit;
}
hasGroups = me.embeddedParams && groupParam && groupers && groupers.length > 0;
if (hasGroups) {
// Grouper is a subclass of sorter, so we can just use the sorter method
if (simpleGroupMode) {
params[groupParam] = groupers[0].property;
params[groupDirectionParam] = groupers[0].direction || 'ASC';
} else {
params[groupParam] = me.encodeSorters(groupers);
}
}
if (me.embeddedParams && sortParam && sorters && sorters.length > 0) {
if (simpleSortMode) {
index = 0;
// Group will be included in sorters, so grab the next one
if (sorters.length > 1 && hasGroups) {
index = 1;
}
params[sortParam] = sorters[index].property;
params[directionParam] = sorters[index].direction;
} else {
params[sortParam] = me.encodeSorters(sorters);
}
}
if (me.embeddedParams && filterParam && filters && filters.length > 0) {
params[filterParam] = me.encodeFilters(filters);
}
return params;
}
});
Usage:
store: Ext.create('Ext.data.Store', {
...
proxy: {
...
type: 'ajax', // or 'direct', 'jsonp' / 'scripttag'
embeddedParams: false
}
})
add the limit property to your store...
limit:50,
and might not hurt to try pagesize....
pagesize:50
and see if either of these help.
Edit : also try
pageParam:undefined,
in your proxy.
found that last piece from...
http://www.sencha.com/forum/showthread.php?118445-CLOSED-1.0.1-Ext.data.JsonStore-quot-limit-quot-param-issue
You can modify the limit param using
store.proxy.limitParam=null;
To remove the _dc parameter on extjs 4 you can set:
noCache: false
or just uncheck the box if you're using architect 2.
Specifically for Json, to get rid of _dc parameter, in your proxy object, set the config option given by Tharahan:
proxy: {
type: 'ajax',
api: {
read: 'app/data/something.json',
update: 'app/data/something.json'
},
reader: {
type: 'json',
...
},
writer: {
type: 'json',
...
},
noCache: false
}
EDIT: (sorry, I did not look at the post date, but lost so much time with it) Please note that the global Ext.Loader.setConfig({disableCaching: false}); does not affect subclasses of Ext.data.proxy.Server which need this specific option (at least in development with sencha touch 2.2.0).
The below code uses Ext.data.Store to retrieve a JSON with table metadata (for the column headings) and the table's data. The backend PHP script is working correctly and the Ext.data.Store contains valid records for the data - I just can't get them to go "into" the Grid itself.
The API Documentation makes it seem as if I just define a store property for Ext.grid.GridPanel and it will handle the rest.
Note: The code below is a separate from the rest of the application. We have pulled this portion out to see if we can just get a grid working, without the influence of the rest of the application.
Ext.BLANK_IMAGE_URL = 'js/ext/resources/images/default/s.gif';
Ext.onReady(function() {
var columns = [];
var fields = [];
var tabPanel = new Ext.TabPanel({
renderTo: Ext.getBody(),
activeTab: 0,
height: 700
});
var queryHeaders = Ext.data.Record.create([
{name: 'id'},
{name: 'table'},
{name: 'field'},
{name: 'title'}
]);
var applicationStore = new Ext.data.Store({
autoLoad: true,
reader: new Ext.data.JsonReader({root: 'fields'}, queryHeaders),
url: 'http://localhost/aargh/index.php/applications/hardware',
listeners: {
'load': function() {
console.info(applicationStore);
applicationStore.each(function(r) {
this_column = [];
this_column['header'] = r.data['title'];
this_column['dataIndex'] = r.data['id'];
columns.push(this_column);
this_column = []
this_column['name'] = r.data['id'];
fields.push(this_column);
});
console.info(fields);
var queryFields = Ext.data.Record.create([fields]);
var queryStore = new Ext.data.Store({
autoLoad: true,
reader: new Ext.data.JsonReader({root: 'fields'}, queryFields),
url: 'http://localhost/aargh/index.php/query/execute/applications/hardware',
listeners: {
'load': function() {
console.info(queryStore);
tabPanel.add(new Ext.grid.GridPanel({
title: 'Hardware',
store: queryStore,
columns: columns,
autoHeight: true,
frame: true
}));
tabPanel.doLayout();
}
}
});
}
}
});
});
As I review the applicationStore and queryStore objects in Firebug I can see the expected data results perfectly in applicationStore.data.items.#.json and queryStore.data.items.#.json (of course, replacing # with the record number).
Any ideas?
Wow - this has been giving us trouble for three days. Turns out I was making an array within an array at var queryFields = Ext.data.Record.create([fields]);
Changing that to: var queryFields = Ext.data.Record.create(fields); fixed the issue.