Kendo Grid is new to me, so I apologize for the ignorance. I'm writing an angular app that uses a separate service to update a local array. It is store in $scope.searchResults variable. I've initialized the grid using the dataSource ->transport property in the hopes that when the array mentioned above is updated, so too will the datasource and the grid updated accordingly. This is not the case. The array is updated, without any problems, but the datasource is never updated. I'll do my best to paste all the code snippets, and console output below.
Html:
<div class="margin-top-25" ng-show="searchResults">
<div id="report-grid" kendo-grid="grid" options="mainGridOptions"></div>
</div>
DataSource proper of the Grid configuration:
dataSource: {
transport: {
read: function read(options) {
options.success($scope.searchResults);
}
},
schema: {
model: {
id: "id",
fields: {
name: {type: "string"},
dataSource: {type: "string"}
}
}
},
pageSize: 10
}
Function for updating the datasource:
function runSearch() {
RetrieveReportsService.query({name: vm.searchData.name, dataSource: vm.searchData.dataSource},
function success(result) {
$log.log($scope.grid.dataSource);
$log.log($scope.searchResults);
$scope.searchResults = result.elements;
$log.log($scope.searchResults);
$scope.grid.dataSource.read();
$log.log($scope.grid.dataSource);
});
}
Now console output:
First time logging the data source:
O…e.e…d.init {options: Object, _map: Object, _prefetch: Object, _data: ObservableArray.extend.init[2], _pristineData: Array[2]…}
First time logging $scope.searchResults:
[Object, Object]
Second time logging $scope.searchResults:
[Object]
Second time logging the data source:
O…e.e…d.init {options: Object, _map: Object, _prefetch: Object, _data: ObservableArray.extend.init[2], _pristineData: Array[2]…}
Note that each data source has an observable array length of 2, before and after the $scope.searchResults has been updated.
I can drill down into the output if it is needed, but didn't want this post to get overwhelming.
Thanks!
Because you are referencing your data that is declared inside your options object by pointing k–options at your options object when the grid initially binds to the options object it's not populated with the data yet. If you reference your data source object separately using k-data-source it will bind to your data source and update your grid when the data source changes. If you want to make changes to your options object trigger a rerender you need to use k–rebind or alternatively the setOptions method. Be sure to read the docs for the latter as there are some caveats.
Well, I don't know why it is working the way that it is, but with the current project configuration this is the solution.
The grid configuration and the function for updating the data source are in the same module. The grid itself is initialized in another controller. I had move the function for updating to the controller that contained the grid and now it works perfectly.
If anyone knows why, feel free to chime in.
Related
Got a server returning a JSON object like so:
{
'key1':'value'
'key2':{
'key2_0':'value'
}
}
And a collection:
var Collection = Backbone.Collection.extend({
url:api.url//which returns the object above
});
var collection = new Collection();
collection.fetch({
success:function(data){
//do something
}
});
Now i need to use certain properties of the collection throughout my application, but say i need key1, i always have to do collection.at(0).get('key1');//returns 'value', because the data returned is stored within the collection, in a new Array at key 0.
Question:
How to directly... collection.get('key1')//now returns undefined... because it is.
I know i could expose an object to the global scope in the collection success function some_other_var = data.toJSON()[0] and access the some_other_var properties directly, but that's not what i'm looking for;
In order to use the get() function from a Backbone.Collection you need to know the model id or cid wanted.
For instance, lets say your data coming from the server is like follow:
[{
id: '123',
name: 'Alex'
}, {
id: '456',
name: 'Jhon'
}]
In that case you can do this:
this.collection.get('123').get('name') // Return "Alex"
Keep in mind that collection is just a set of model, so behind the scenes by doing collection.get() you are getting a model
Tip: If you don't have any kind of id in your server data, there is always the option of using underscore methods:
find
filter
some
contains
etc
It seems like you're trying to ascribe attributes to a collection, but a collection is merely a set of models. Having additional data that is constant throughout the collection suggests that it should be wrapped inside another Model, which is demonstrated here: Persisting & loading metadata in a backbone.js collection
A grid has editable rows, connected to a store which has a proxy.
It uses the api e.g.
proxy: {
type: 'ajax',
api: {
create: 'dm/acct/new.php',
read: 'dm/acct/read.php',
update: 'dm/acct/update.php',
destroy: 'dm/acct/rm.php'
},
extraParams: {
sess: 2345
},
If I add extraParms to the store's proxy e.g. {abc:123} as shown above, when I come to edit a field on a grid, that detail is accompanied by the record at the server with the value defined. I can inspect it in the read.php.
However, for testing, I tried replacing abc with an application level var, e.g.
{abc:RPA.app.A_GLOBAL_VAR}
results in
Uncaught TypeError: Cannot read property 'A_GLOBAL_VAR' of undefined - this surprised me since the var is declared at the Application level and I thought would be scoped and available. This error causes the application to fail to run at all.
I have got it working but I don't like my approach because I think it is using the wrong event and I have not been able to spot a more suitable one.
On the grid' cell dblClick event I have:
var sto = Ext.getCmp('acc_grid').getStore();
var proxy= sto.getProxy();
proxy.setExtraParam('abc', somevar );
I definitely get the value of abc:somvar server-side - so does what I want. I just think it is bad design/wrong event and wondered if there is a better way of attaching the extra param to the record when the update on an editable grid? I have looked at other examples but not stumbled across one that I have been able to relate to.
Many thanks
Kevin
Listen to the CellEditor plugin edit event rather than the cell dblclick...
http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.grid.plugin.CellEditing
When you set your cell editing plugin...
plugins: [
Ext.create('Ext.grid.plugin.CellEditing', {
clicksToEdit: 1,
listeners:{
edit:function(){ doSomething }
}
})
],
Suppose I have following Backbone.js model:
class App.Models.Article extends Backbone.Model
defaluts:
id: ''
name: ''
tags: []
and a view to display its contents. In a master view I create an instance of article view by passing a newly created Article as :
v = new App.Views.ArticleView({ model: new App.Models.Article() })
and render it to the page.
In the article view and by user interaction some tags are added to the tags array by following code:
addTag: ->
tags = #model.get('tags')
tags.push({id: '', name: 'foo'})
tags.push({id: '', name: 'bar'})
So far so good! Then I close the article view and render another view. Later I want to again render the article view so the code:
v = new App.Views.ArticleView({ model: new App.Models.Article() })
runs again.
The problem is after rendering, I still can see previously entered tags in the tags array i.e. if inside articles view, I write:
console.log(#model.get('tags'))
it will output two objects added before. I expect that each instance has its default values when created not something that there is no more reference to it. Any ideas? Any issues with Coffescript?
P.S. I hope the problem statement is clear enough :)
Don't use arrays and objects in defaults, they will get shared across model instances. If you want tags to be empty array, add that in initialize function.
var MyModel = Backbone.Model.extend({
initialize:function(){
this.set('tags', [])
}
})
Solved!
The problem is that Coffeescript attaches default to the prototype, so defining the defaults as follows solves the problem:
defaults: ->
id: ''
name: ''
tags: []
Again it is attached to the prototype but as a function, it returns an empty object for each call.
I need to get(retrieve) updated cell value in controller. (MVC)
So I tried this,
var modified = this.getItemGrid().getStore().getUpdatedRecords();
console.log(modified); // return [] empty array
var modified = this.getItemList_Store().getUpdatedRecords();
console.log(modified); // return [] empty array
but always it returns empty array even I updated some cell value.
anybody know what I am doing wrong?
Here is my part of view code,
Ext.define("App.view.orders.ItemList_view", {
extend: "Ext.grid.Panel",
alias: "widget.itemList_view",
plugins: [
Ext.create('Ext.grid.plugin.CellEditing', {
clicksToEdit: 1
})
],
initComponent: function () {
this.store = "ItemList_store";
this.columns = [
{
xtype: 'checkcolumn', text: "Ship", width: 50, dataIndex: "DR"
},
{ header: "test", width: 100, dataIndex: "test",
editor: {
xtype : 'textfield'
}
}
];
this.selModel = Ext.create("Ext.selection.CheckboxModel");
//this.selModel = Ext.create("Ext.selection.CellModel"); // It does not works either.
this.callParent(arguments);
},
.
.
.
Thank you!
[EDIT]
Thank you very much for your answer! I have some more question about editor grid.
Its much different from Ext3. so I'm very confusing now :(
Q1. How to collect edited record data (once click button)?
the event fired once the grid cell be changed.
but I want collect edited grid record once I click the 'Update edited cell' button, and I want to update all together at the once.
In Ext3, I did like this,
(button) click : function(){
var modified = mygridStore.getModifiedRecords();
var recordsToSend = [];
Ext.each(modified, function(record){
recordsToSend.push(record.data);
});
var grid = Ext.getCmp('grid');
grid.el.mask('Updating','x-mask-loading');
grid.stopEditing();
recordsToSend = Ext.encode(recordsToSend);
Ext.Ajax.request({
url : '/test/test',
params : {
data : recordsToSend
},
success : function(response){
grid.el.unmask();
alert(response.responseText);
mygridStore.commitChanges();
},
failure : function(response){
mygridStore.rejectChanges();
}
});
}
How can I change the code for Extjs4 ?
Q2. I don't know still how to find out for changed checkcolumn.
I tried this, but I does not work for checkcolumn (of cause I tested after change checkbox)
// grid coumn
{
xtype: 'checkcolumn', header: "My Check Column", width: 50, dataIndex: "CH"
}
-
// in control
'myGrid': {
validateedit: function (plugin, edit) {
console.log(edit);
},
checkchange: function (plugin, edit) {
console.log(edit);
console.log(edit.value);
}
}
Q3. When I click the cell to edit, the show some HTML tag in -_-;;
I really appreciate for your help. and thank you very much for your valuable time!
The editors (cell editors or row editors) do not commit their values to the store until you complete the edit - which means pressing ENTER or blurring the active cell editor by clicking elsewhere on the page, or clicking the save button on the row editor form .
If your purpose for reading the updated value in your editor is to perform some kind of validation I would suggest simply listening to the validateedit event in your grid's controller, as described here.
The second argument that this event passes to your handler contains a lot of data about the edit that you can then perform validation with. If the edit doesn't pass your validation you can return false from your handler and the value in the celleditor will revert to it's original value. The validateedit event gets fired from the editor grid itself so you would add an event handler in your controller for it like this:
Ext.define('MyApp.controller.MyController', {
init: function() {
this.control({
'mygridpanel': {
validateedit: function(plugin, edit) {
// silly validation function
if (edit.value != 'A Valid Value') {
return false;
}
},
},
});
},
});
But you should check out the link above to see all the different objects available in that second argument I named edit.
The validateedit event is fired right before the record is committed into the store - after the user has already clicked ENTER or blurred the editor, i.e., while the editor is closing.
If you are trying to get the celleditor's value before it starts to close, for some reason other than validation for example, you could get the active celleditor's value like this:
// myGrid is a reference to your Ext.grid.Panel instance
if (myGrid.editingPlugin.editing) {
var value = myGrid.editingPlugin.getActiveEditor().field.value
console.log('value: ' + value);
}
If there is no active editor then myGrid.editingPlugin.getActiveEditor().field would throw an error, that's why I wrapped a conditional around it.
One other point I should make, for validation in editor grids, I found that it is easiest to just put a validator config in the grid column's editor definition. That will give you all the handy validation CSS while the user is setting the field's value and alert him if there is a problem with the value before he tries to save it.
To get an idea of what I mean, try entering letters in the date column of this example. Mouse over the editor cell and you will get the error message.
EDIT
It seems I misunderstood you original question, I'll break down my answers to your questions above though,
Question 1
Once you have completed an edit (clicked ENTER or ), your call to mygridStore.getModifiedRecords() should be working fine because the record will have been committed to the store. I see that it was not working, I will cover that in a moment.
I should point out that ExtJS4 has a store.sync() method as covered here.
Instead of extracting the modified records from the store, encoding them, manually doing an ajax request to save them to the server and then manually committing them you can call this sync method and it will take care of all of these actions for you.
If you have different URLs to handle the different create, read, update, destroy operations fired off by your store's load and sync methods, you can use the store's proxy api config to map your URLs to these operations as covered here. Or you can set-up your server side controller to be able to differentiate between your store's load request (read operations default to HTTP GET) and it's sync requests (create, update and delete operations default as HTTP POST).
There could be many different ways to go about doing this on the server side, the way I usually do it is to have one SQL stored procedure for GET requests and one for POST requests for any given store. I include the store name as an extra param and then my server side controller runs the appropriate stored procedure based on whether it is a GET or a POST request.
Question 2
Cell editing doesn't support checkcolumn edits. You have to make a different handler to listen to changes on that, something like this:
checkchange: function (column, rowIndex, checked) {
var record = store.getAt(rowIndex),
state = checked ? 'checked' : 'unchecked'
console.log('The record:');
console.log(record)
console.log('Column: ' + column.dataIndex);
console.log('was just ' + state)
}
Your call to mygridStore.getModifiedRecords() should be able to pick up the check changes also however, they get committed to the grid's store right away after being checked. store.sync() would also pick up changes to checkcolumn.
Question 3
I can't completely tell what is causing that problem but it may be something strange going on with your validateedit event, your handler should be returning true or false.
As I said earlier, I misunderstood the reason you originally asked this question. I thought you were trying to do some kind of validation while an edit was in progress. Now I understand that you are trying to get all of the modified records from the store after all the editing is completed in order to save them to the database, I was thrown off because in ExtJS 4 a store is usually saved to the database with the sync method as I mentioned.
In other words, you don't need the validateedit event or checkchange event to get a list of modified records.
The actual problem you are having might be trouble with the store's getter methods (getModifiedRecords, getUpdatedRecords) in some 4.07 versions, take a look at this post and this one.
So with all that said, the best advice I can give you is 1) try out the stores sync method for saving modified data to the database and 2) upgrade to ExtJS 4.1, there were a lot of bugs that were straightened out between 4.07 and 4.1 which you should be able to take advantage of, I cut out about 75% of the overrides I was using to make things work when I switched over to 4.1.
EditedGrid.plugins[0].completeEdit();
This will make the active changes commit and call edit event also.
listeners: {
validateedit: function (editor, e) {
//console.log(editor);
var oldVal = editor.originalValue;
var newVal = editor.value;
}
}
I have a grid bound to a form the forms submit action is to update the loaded record if there is one and add a new record if its a blank form. but if I select a record first and then call
myGrid.getSelectionModel().deselectAll();
myform.getForm().reset();
to clear the form so I can add a new record it overwrites the previously selected record with an update.
record = myform.getRecord();
if(record){
record.set(values);
}
shouldn't myform.getRecord(); be null after a reset? how do I clear the record selection?
In short, no, it shouldn't and you don't have legal approaches to clear the record after the first time you load anything via loadRecord.
Although, you could still do myform.getForm()._record = null assignment, I would strongly object against that, as it may break some internal functionality by ExtJS.
Here is an extract from ExtJS API:
getRecord() : Ext.data.Model
Returns the last Ext.data.Model instance
that was loaded via loadRecord
And it does exactly that, returns the last record loaded via loadRecord.
Here are some sources:
getRecord: function() {
return this._record;
},
loadRecord: function(record) {
this._record = record;
return this.setValues(record.data);
},
Actually, those are the only methods of Ext.form.Basic (an instance of which is returned by getForm()) dealing with this._record field.
As for reset
reset: function() {
var me = this;
me.batchLayouts(function() {
me.getFields().each(function(f) {
f.reset();
});
});
return me;
},
As you could see, reset has nothing to do with the record returned by getRecord(), it's just resetting field values.
For anyone interested, you can override the default form panel to add functionality to clear form fields. Add the following to your code:
Ext.override(Ext.form.Panel, {
clearForm:function(){
Ext.each(this.getForm().getFields().items, function(field){
field.setValue('');
});
}
});
You can then clear a form using:
myForm.clearForm()
Where myForm is your form panel.
This is what you looking for:
form.getForm().reset(true);
True to unbind any record set by loadRecord.
See Ext.form.Basic.reset() syntax
I find this question because I have a similar scenario but slightly different:
ExtJS 4.1.1
TreePanel
In ExtJS 4.1 in sync() method you can use an options object in which you can define a callback, success and failure functions. Since I'm sure I'm only synchronozing just one record, I loaded the returned record:
me.getHelpItemsStore().sync({
success: function(batch) {
// We expect single operation so...
var record = batch.operations[0].getRecords()[0];
form.loadRecord(record);
}
});
Little late but hope helps you.