how do I define a nested store for ext.js using ext.net - extjs

Platform - Ext.net 2.1 in an MVC project. The data is coming back as json from a DirectMethod and I'm binding on the client.
I'm returning the results of a dataset with multiple tables with relationships defined between the tables. I want to bind the resulting data to a store to be used in a dataview. The first dataview that I'm filling, only uses the highest level of data. However, when the user selects a record in the dataview, I want to bind to another template in a different dataview to provide all levels of information.
Tables
Account
--- Addresses
(I'll skip the other table for now)
Here is the definition of my models and store:
#(Html.X().Model()
.Name("SearchResults.Models.Address")
.IDProperty("nafnmfuid")
.Associations(assoc => assoc.Add(new BelongsToAssociation() {Model = "SearchResults.Models.Account"}))
.Fields(
new ModelField("nafnmfuid", ModelFieldType.Int),
new ModelField("naftype"),
new ModelField("nafadd1"),
new ModelField("nafcity"),
new ModelField("nafstate"),
new ModelField("nafzip")
))
#(Html.X().Model()
.Name("SearchResults.Models.Account")
.IDProperty("nmfuid")
.Associations(assoc => assoc.Add(new HasManyAssociation() {Name = "Addresses", Model = "SearchResults.Models.Address", AssociationKey = "Addresses", PrimaryKey = "nmfuid", ForeignKey = "nafnmfuid"}))
.Fields(
new ModelField("nmfuid", ModelFieldType.Int),
new ModelField("AmfLastNamePrimary"),
new ModelField("AmfFirstNamePrimary"),
new ModelField("nmfid"),
new ModelField("naftype"),
new ModelField("nafadd1"),
new ModelField("nafcity"),
new ModelField("nafstate"),
new ModelField("nafzip")
)
)
#(Html.X().Store()
.ID("StoreSearchResults")
.ModelName("SearchResults.Models.Account")
.Reader(readers => readers.Add(Html.X().JsonReader()))
)
I tried returning the data as nested json as well as three objects in the json.
When I bind the data (on the client), I get the new field in the highest level (Account) called Addresses. However, the field is an empty array.
When I look at the RAW property of the Account record, I see all the nested data.
Here is the ext.js code that's generated by Ext.net
window.App.StoreSearchResults2 = Ext.create("Ext.data.Store", {
model:Ext.define("SearchResults.Models.Address", {
extend: "Ext.data.Model"
, fields:[ {
name:"nafnmfuid"
,type:"int"
}
, {
name:"naftype"
}
, {
name:"nafadd1"
}
, {
name:"nafcity"
}
, {
name:"nafstate"
}
, {
name:"nafzip"
}
]
,idProperty:"nafnmfuid"
,associations:[ {
type:"belongsTo"
,model:"SearchResults.Models.Account"
}
]
})
,storeId:"StoreSearchResults2"
,autoLoad:true
,proxy: {
type:'memory'
, reader: {
type:"json"
}
}
});
window.App.StoreSearchResults = Ext.create("Ext.data.Store", {
model:Ext.define("SearchResults.Models.Account", {
extend: "Ext.data.Model"
, fields:[ {
name:"nmfuid"
,type:"int"
}
, {
name:"AmfLastNamePrimary"
}
, {
name:"AmfFirstNamePrimary"
}
, {
name:"nmfid"
}
, {
name:"naftype"
}
, {
name:"nafadd1"
}
, {
name:"nafcity"
}
, {
name:"nafstate"
}
, {
name:"nafzip"
}
]
,idProperty:"nmfuid"
,associations:[ {
type:"hasMany"
,associationKey:"addresses"
,primaryKey:"nmfuid"
,model:"SearchResults.Models.Address"
,foreignKey:"nafnmfuid"
,name:"Addresses"
}
]
})
,storeId:"StoreSearchResults"
,autoLoad:true
,proxy: {
type:'memory'
, reader: {
type:"json"
}
}
});

The problem was that I was using the method loadData on the client to bind the data. Switching to loadRawData did the trick.

Related

Select All checkboxes by default in nested mat table not working as expected

I have a nested mat table with expandable rows . Only the inner table has checkbox and by default all the checkbox has to be checked in all the nested tables . Here is the working stackblitz
https://stackblitz.com/edit/angular-nested-mat-table-triplenested-iavs62?file=app%2Ftable-expandable-rows-example.ts
getProjectDetails(element: any) {
console.log(element.Id);
this.tableService.getInnerData(element.Id).subscribe((res) => {
if (res.length == 0) {
element['usersdataSource'] = new MatTableDataSource();
} else {
element['usersdataSource'] = new MatTableDataSource(res);
this.userSelectionMap.set(
element.Id,
new SelectionModel<any>(true, [element['usersdataSource']])
); // provided datasource of the current inner table for default sselection
}
});
}
I have provided the value of datasource for default selection while defining the selection model but it is not working as expected . I dont want to iterate over each table and do the selection as the data of inner table can be huge . What could be the best way to implement this ?
When you instantiate your SelectionModel, you need to pass element['usersdataSource'].data instead of [element['usersdataSource']].
getProjectDetails(element: any) {
console.log(element.Id);
this.tableService.getInnerData(element.Id).subscribe((res) => {
if (res.length == 0) {
element['usersdataSource'] = new MatTableDataSource();
} else {
element['usersdataSource'] = new MatTableDataSource(res);
this.userSelectionMap.set(
element.Id,
new SelectionModel<any>(true, element['usersdataSource'].data) // here
); // init userSelection of the current inner table
}
});
}

ExtJS - Grid filter with multiple columns and multiple values

I create a grid and a toolbar with Two Menu of menuCheckItem. When i check the menuCheckItem the grid filters even with multiple values and multiple columns.
This working fine, as I have created grid 1st and then the toolbar
this.up('') // Used Instead of Ext.getCmp()
Working FIDDLE - https://fiddle.sencha.com/#view/editor&fiddle/2lop
Now I am trying to create same toolbar along with Menu separately on top 1st and then create grid at below. But while doing this, nly Multiple values is working.
I am trying to filter grid with multiple values as well as multiple columns.
Few things i tried -
// Only Filters One Value at a time with each Columns
store.queryBy(function(record,id){
return (record.get('name') == someValue && record.get('phone') == otherValue);
});
and
// Filters Many Columns with Single Value
filter.add(
property : name, phone
value : "somevalue"
operator : "OR"
);
Is there any way to implement Toolbar 1st and then grid ? And Filter grid with many values and columns simultaneously ?
In this FIDDLE i remade a function(checkchange), which is universal , can be put separately and you'll be able to attach it to every menucheckitem you create. The only thing is that if you add new menucheckitem filter you should name the menucheckitem id with the name of the columnDataIndex-Menu and add this columnDataIndex in menuFilters and thats all.
checkchange: function (checkbox, checked, eOpts) {
var menuFilters = ['name', 'phone'];
var getChecked = function (m) {
var checkedItems = [];
m.items.items.forEach(function (c) {
if (c.checked) {
checkedItems.push(c.text);
}
});
return checkedItems;
};
//
var menus = new Map();
menuFilters.forEach(function (e) {
menus.set(e, Ext.getCmp(e + '-Menu'));
});
//
var fieldValues = [];
menuFilters.forEach(function (e) {
fieldValues.push([e, getChecked(menus.get(e))]);
});
//
var store = checkbox.up('grid').store;
store.clearFilter();
//
if (fieldValues.length > 0) {
store.filterBy(function (record) {
var fV = this.fieldValues;
for (var i = 0; i < fV.length; i++) {
if (fV[i][1].length > 0) {
if (fV[i][1].indexOf(record.get(fV[i][0])) === -1) {
return false;
}
}
}
return true;
}, {
fieldValues: fieldValues
});
}
}

Merging arrays in Knockout

In my knockout app I have two observable array. One is Location,
self.locations = ko.observableArray([]).withIndex('id');
This contains all the locations. The locations can be associated to a project or not. If the locations don't exists in the project it will have project id null.
The other array is of projects. It contains all the projects if they have any location it has an array of locations.
Now what I am trying to do is to get an array with the combination of two something like this
displayLocations = {
location1 = {name = "abc", ...}
... these don't have any projects
location9 = {name = "xyz", projectName = "project1", .. }
}
I am trying to create a computed property for that and then on the view side I am thinking of using different templates depending upon if the location has project or not.
any suggestions?
Not sure about the withIndex method, but with vanilla KO you can use ko.utils.arrayMap inside a computed:
this.associatedLocations = ko.computed(function() {
var dataLoc = this.locations(),
dataProj = this.projects(),
result = ko.utils.arrayMap(dataLoc, function(loc) {
var newObj = loc, project;
if (loc.projectId !== null) {
project = ko.utils.arrayFirst(dataProj, function(proj) {
return proj.id === loc.projectId;
});
newObj.projectData = proj;
}
return newObj;
});
return result;
}, this);
// assumes locations have a 'projectId' & 'name' property, & projects an 'id' property
// will return an array in the form of
// [ {name: 'xyz', projectData: { id: ..., projectName: ...}}]
You can test whether a location is associated with a project by doing:
<div data-bind="template: {
name: obj.projectData ? 'nameIfProject' : 'nameIfNoProject' }">
</div>

ExtJS - Drag column header to other grid

I need keep the default feature of reordering columns and add
possibility drop the column in a second grid, building in the last a list
with the columns of first grid.
I hope has been clear.
I solved the issue extending DropZone. This implementation receive as constructor param the target grid, and this, be in the rbar (docked control) of source grid. The key is set ddGroup to "header-dd-zone-" plus id from source grid. I hope this is useful.
Ext.define('Crud.FilterDropZone', {
extend: 'Ext.dd.DropZone'
, constructor: function() {}
, init: function (grid) {
var me = this;
if (grid.rendered) {
me.grid = grid;
me.ddGroup = 'header-dd-zone-' + grid.up('grid').id;
grid.getView().on({
render: function(v) {
me.view = v;
Crud.FilterDropZone.superclass.constructor.call(me, me.view.el);
},
single: true
});
} else {
grid.on('render', me.init, me, {single: true});
}
}
, getTargetFromEvent: function (e) {
return {};
}
, onNodeDrop: function (nodeData, source, e, data) {
var header = data.header
, store = Ext.getCmp(e.target.id).getStore();
//store.add(new store.RecordType({ property: header.text, value: '', reference: header.dataIndex}));
store.add([[header.text, '', header.dataIndex]]);
}
});

how can I update a model with custom idAttribute

in my simple backbone application, I am trying to update a model and every time it send a put request instead of post.
Well, this is my model named categoryModel
define(['Backbone'], function (Backbone) {
var CategoryModel = Backbone.Model.extend({
defaults: {
ID: '',
Name: 'Empty',
TagID: '0',
GID: '0'
},
idAttribute: "ID",
initialize: function () {
if (!this.get('Name')) {
this.set({ 'Name': this.defaults.Name });
}
}
});
return CategoryModel;
});
this is the collection
define(['Backbone','../../models/categories/categoryModel'], function (Backbone, categoryModel) {
var CategoryCollection = Backbone.Collection.extend({
url: '/parentcategory/Actions',
model: categoryModel
});
return new CategoryCollection;
});
here are my methods in the view
on a keychange event
createNewItem: function (e) {
var $this = $(e.currentTarget);
$('#selectedCategoryName').html($this.val());
//it creates a new model
globals.NewCategory = new CategoryModel({ Name: $this.val() });
}
on handleDrop event
handleDropEvent: function (event, ui) {
var draggable = ui.draggable;
//check if name has set
if (!globals.NewCategory) {
alert("Please write a category name");
$('#createNewCategory').focus();
return;
}
//get itemID
var itemID = draggable.attr("id").split('_')[1];
var itemDesc = draggable.attr("id").split('_')[0];
//check items category
if (itemDesc == "Tag") {
//check if tagID already exists
if (globals.NewCategory.TagID) {
alert("you have already specify a tag from this category");
return;
}
globals.NewCategory.set("TagID", itemID);
} else if (itemDesc == "gTag") {
if (globals.NewCategory.GID) {
alert("you have already specify a tag from this category");
return;
}
globals.NewCategory.set("GID", itemID);
}
categoriesCollection.create(globals.NewCategory, {
silent: true,
wait: true,
success: function (model, response) {
model.set("ID", response);
alert(model.id);
}
});
}
The categoriesCollection.create is called twice. Firstly for setting the TagID (on a success request it gets an ID ) and secondly for setting the GID.
Since the ID has been set, shouldn't had sent a POST request instead of PUT on the second call?
What am I doing wrong?
Thanks
The standard behaviour is to send a POST if the model is new ( doesn't have an ID attributed ) and send a PUT if the model id is set.
In your case it's working as designed, if you want it to use POST to send UPDATES you have to override Backbone.sync to work as you need, but I think it's easier for you to make your backend RESTful and create a PUT listener controller method for updates.
Another thing, if I got it right you are using create() to update models in your collection, I would advise you not to do that and instead use the save() directly in the model you want to update, the code will be a lot more readable.
Cheers.

Resources