I have two associated models, User and Order. A User has many Orders.
Ext.define("User", {
extend: 'Ext.data.Model',
fields: [
'id', 'name'
],
hasMany: {model: 'Order', name: 'orders'},
proxy: {
type: 'ajax',
url : 'users.json',
reader: {
type: 'json',
root: 'users'
}
}
});
Ext.define("Order", {
extend: 'Ext.data.Model',
fields: [
'id', 'total'
],
belongsTo: 'User'
});
I'd like to display all of the Users in one grid panel, and all of the orders in another grid. I know how to show all of the Users in a grid, I simply define a store with the User model. But I'm a bit lost as to how to show all of the orders in a separate grid. Do I have to define a separate store? What proxy do I use? Anyone have insight? Basically, I just need a conceptual understanding.
I believe what you are asking for is a fairly common use case. Unfortunately ExtJs is not yet able to cope with this out of the box, simply as currently each grid is bound to a store, but your orders store is created on the fly every time you access it through its user association.
The good news is that you have various ways to achieve this. The best one I can think of is that every time the user clicks on a user row, you get your orders store (user.orders()). Then you can reconfigure your grid with this new store.
Usually each Grid needs its own Store. Showing all orders will work the same way as showing all users, just change the Store ID and it should be okay.
Related
I am using Sequelize for Node and I have Users and items. A user can interact with an item in multiple ways, such as voting, or commending (two different things in this case).
My initial thought was to have two different many to many relationship but Sequelize only has one removeItem call, and I haven't figured out how to specify which.
Plan 2 was to build one many to many table with an extra element "type" so I could specify the kind. I can specify the type when the thing is added. This ran into two problems, one they are forign keys and by default that made the pair unique. I corrected this by removing the constraint manually from the DB, and that seemed to be sufficient (I set an id as primary key autoincrement). Secondly, I cannot seem to figure out how to make the delete specify where type = the type I want.
Code:
To build the table:
var UserActions = sequelize.define('userActions', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
type: DataTypes.STRING
});
To remove the item:
models.Item.findOne({where: {id : params.itemID}}).then(function (video){
models.User.findOne({where: {id : params.itemID}}).then(function (user){
if(params.applaud == "true") {
console.log("Add applaud");
user.addItem(video,{type:"commend"});
} else {
user.removeItem(item,{where: {type:"commend"}});
console.log("Remove, Commendation");
}
res.json({'response' : 'Success'});
});
});
The issue is this will delete all interactions between the item and the user, when I want it to only delete the commendation.
How do I best manage multiple many to many relationships between the same two tables in Sequelize?
OK I figured it out.
On the association you have to specify an alias via 'as'
User.belongsToMany(models.Item, {through: 'votes', as: 'votes'});
User.belongsToMany(models.Item, {through: 'commend', as: 'commend'});
Then you can add query with:
models.Item.findOne({where: {id: item.id},
include: [{
model: models.User,
as: 'votes'
}]
})
You can add with:
user.addVote(item);
or
user.addCommend(item);
And delete with:
user.removeVote(item);
or
user.removeCommend(item)
And it works as desired.
Is there a way to add an option to a combobox without modifying the underlying data store in any way? I have 2 combobox elements in my form. The only difference between the two comboboxes is that one has an additional 'All' option. For example:
var states = Ext.create('Ext.data.Store', {
fields: ['abbr', 'name'],
data : [{"abbr":"AL", "name":"Alabama"},
{"abbr":"AK", "name":"Alaska"},
{"abbr":"AZ", "name":"Arizona"}]
});
//The first combobox should load the data as is from the store above
Ext.create('Ext.form.ComboBox', {
fieldLabel: 'Choose State',
store: states,
queryMode: 'local',
displayField: 'name',
valueField: 'abbr',
renderTo: Ext.getBody()
});
//There should be a second combobox here that is almost identical
//to the one above, just appending an additional option (that says "All")
//to the top of the list
I'm aware that there are various ways to alter the store such as:
states.insert(0, [{
abbr: 'All',
name: 'All'
}])
However, I want to achieve this without altering the store, purely adding the option to the combobox itself. Is this possible?
UPDATE
I am aware that I could make the I could set the combobox 'emptyText' configuration option to 'All', but this is not what I want. I would like to have 'All' as an actual option.
Combo is a simple SELECT field of HTML. Without OPTION you cannot populate the dropdown.
Its not possible to achieve it without adding into store. Data you see in the combo comes from store.
According to the docs :
A combobox control with support for autocomplete, remote loading, and many other features.
A ComboBox is like a combination of a traditional HTML text field and a field; the user is able to type freely into the field, and/or pick values from a dropdown selection list. The user can input any value by default, even if it does not appear in the selection list; to prevent free-form values and restrict them to items in the list, set forceSelection to true.
The selection list's options are populated from any Ext.data.Store, including remote stores. The data items in the store are mapped to each option's displayed text and backing value via the valueField and displayField configurations, respectively.
I have already made comboboxes with "All", I hope I get it right, haven't got the source code available right now, but to create an "All" option for one of the comboboxes, in ExtJS 6 you have to do something like this:
var storeWithAll = Ext.create('Ext.data.Store',{
url:
proxy: etc.
listeners:{
load:function(store) {
// Add the "All" record after every load!
store.insert(0, [{
abbr: 'All',
name: 'All',
special:true
}]);
}
}
});
var storeWithoutAll = Ext.create('Ext.data.ChainedStore',{
// ChainedStore has the same data as the source:
source: storeWithAll,
filters:[{
// Filter away the "All" record
filterFn:function(item) {return !item.get("special");}
}]
});
Ext.create('Ext.form.field.ComboBox',{
store: storeWithAll, // Use the store with "All" record
...
});
Ext.create('Ext.form.field.ComboBox',{
store: storeWithoutAll, // Use the store without "All" record
...
});
Have a project on ext js 6. I'm a newbie in it, but I have read a docs, experimented on it, but didn't understood anything. The point of trouble is: there is a form, which has binding to the model.
Form fields:
{
xtype: 'checkboxfield',
fieldLabel: 'Field1',
bind: '{someField1}'
},
{
xtype: 'textfield',
fieldLabel: 'Field2',
bind: '{someField2}'
}
Model fields:
{
name: 'someField1',
type: 'boolean',
mapping: 'some_field_1'
},
{
name: 'someField2',
type: 'string',
mapping: 'some_field_2'
},
As I understand it, every field which has the model, transmitted to server. And this field described by "name" key.
But question is, what if I need, that in model would be few fields, with the same names? But form fields connected to model by name, and an interpreter will not understand which fields do I need..
So I need that model fields would have different names, but transmitted to server with the same name. Is there a possibility to do this?
Because there is a server response, and "mapping" grabs the model field and insert it into form input. But it doesn't work vise versa, and client sends value with "name" key. Help me to understand and solve this problem, please)
If you update the bind code on the view to look like this
bind: {
value : '{someField1}'
}
you can probably set the name then independent of the binding.
I create backbone collection from server JSON. Data is from mongo so each item has same objects and backbone remove this duplicates. It's unwanted behavior for me so, I can't find solution to keep this instances. After fetch my items has only 'section1' in secound object (id:2). I need the same section also in first object. For example my server response is:
items: [{
id:1,
sections: [{
id: 1.//this object is removed
name: 'section1'
}]
}, {
id: 2,
sections: [{
id:1.
name: 'section1'
}]
}]
My section model is just:
Section = Backbone.RelationalModel.extend({
});
and Item model:
Item = Backbone.RelationalModel.extend({
relations: [
{
'type': 'HasMany',
'key': 'sections',
'relatedModel': 'Section',
'includeInJSON': 'id',
'reverseRelation': {
'key': 'item',
'includeInJSON': 'id'
}
}
]
});
If I recall correctly, this plugin doesn't support many-to-many. So, what's happening is that it is attaching Section 1 to the first Item, then attaching it to the second and removing it from the first.
In fact, from the docs:
Backbone.HasMany
Defines a HasMany relation. When defining a reverseRelation, the type
will be HasOne.
Your options:
Create a SectionItem model that HasOne Section and HasOne Item. Someone posted a fiddle with this sort of setup http://jsfiddle.net/mmacaula/XaESG/2/
Use another library - or an extension of the one you use, like https://github.com/jj-studio/Backbone-JJRelational
Add a property to the Section model key that would make each one unique. This is not a good way to achieve what you are trying to do, though.
Here is a pretty good reference answer: Implementing a Many-to-Many relationship with Backbone-Relational
Sometimes we use one store for few views(list, carousel,dataviews) and when we refresh(load, filter) store data, dom of all view that use this store will be rebuild, but some views is not displayed in this time, and may be will not show with these data. How we can refresh list dom only if it displayed, not every time when it store refresh?
Issue examle
Ext.define("Test.view.Main", {
extend: 'Ext.tab.Panel',
config: {
tabBarPosition: 'bottom',
items: [ ]
},
constructor : function(){
this.callParent(arguments);
var store = Ext.create('Ext.data.Store',{
data :[
{title : 'One'},
{title : 'Two'},
{title : 'Three'}
]
}),
firstList = Ext.create('Ext.List',{
title : 'tab1',
store : store,
itemTpl : '{title}',
onItemDisclosure : function(){
store.add({title : 'Four'});
}
}),
secondList = Ext.create('Ext.List',{
title : 'tab2' ,
store : store,
itemTpl : '{title}'
}),
thirdList = Ext.create('Ext.List',{
title : 'tab3',
store : store,
itemTpl : '{title}'
});
this.add([
firstList,
secondList,
thirdList
]) ;
}
});
When tap on item in the first list, in store will be added new item. And dom of all list will be change although second and third list not displayed
I see one option. Create one main store and create separate stores for each views. And when view show fill it store from Main store. But it look not good. Any other ideas?
As far as I know, there is no "out-of-the-box" solution. The docs say that the refresh event is preventable, but I haven't tested that theory.
One other idea would be to look at the dataview source and override parts of it.
The starting point would probably be to look at the store event hooks that you can find there:
storeEventHooks: {
beforeload: 'onBeforeLoad',
load: 'onLoad',
refresh: 'refresh',
addrecords: 'onStoreAdd',
removerecords: 'onStoreRemove',
updaterecord: 'onStoreUpdate'
}
However it would probably be tedious work perfecting it.
On the other hand, your DOM shouldn't be refreshed for the other lists when adding a new record, it should only add a new list item to each list so disabling the addrecords event and then doing a complete refresh of the other lists when they are displayed will probably be more ineffective?