I'm new to Extjs 4 and I'm trying to understand how to create a model for data that has nested objects.
Example Data:
{
data1:{
field1:1,
field2:2,
**objField1**:{
objField1:1,
objField2:2,
**anotherObj**:{
field1:1,
field2:2,
arrayofObjs:[
{
//...
},
//...
]
}
},
objField2:{
//... Some more fields or objects
},
data2:{
//...
}
}
I'm trying to understand how I would model this data. The fields are easy
Ext.define('MyModel', {
extend: 'Ext.data.Model',
fields: [
{name: 'field1', type: 'int'},
{name: 'field2', type: 'int'}
], //...
But how do you model the objects? I was thinking I could create a model for the sub-objects and setup associations, but after reading the documentation, they seem to need to have IDs. So if you look at the belongsTo page, "The owner model is expected to have a foreign key which references the primary key of the associated model".
I'm not looking to model data that has foreignkey relationships, just objects with sub-objects. So the server might return one JSON object with multiple sub-objects, and one of those objects I might want to tie to a grid, another object's data to a selectbox, etc.
Thanks!
I think you have several problems here.
First, Models in Ext JS are mostly used to represent relational data, i.e. rows in SQL database. You can twist them to do whatever you want, but that doesn't mean it would be easy and there's always the question of "what for".
Second, Ext.data.Model is not suited at all for representing tree-like structures; you can use Ext.data.NodeInterface for that. NodeInterface is kinda class override for Model, a mixin in part, and generally is quite kludgy and rigid thing. The bright side is that it works, and the down side is that there's no other class that does the same stuff.
Next, nested data objects do not necessarily mean that they're actually related to each other. You said you want to pluck objects from one global JSON response; this can be done easily by configuring multiple Stores with different Readers and feeding them the same JSON object.
OTOH, the data structure looks a bit convoluted. Is that an attempt at preliminary optimization on the server side? I.e., put all stuff we might need into one huge JSON to save on server hits? If so, take a look at Ext.Direct remoting; it can save you from lots of headache down the road.
Related
I have MERN application, I have a bunch of collections in my db, now i want to store an object that represents an order:
Say i have "item1, item2, item3" in an "items" collection, each one can be anything really;
I just need the Id's (to reference them), I want the user to choose their order so that i know the correct way of displaying the items (Not the order in the db, an order for a seprate purpose)
I think the best way of doing it is having a single document, with the order data in it, but each document should be in a collection, so the question is, is it right to create a collection only to store a single document in it? or is there a better way?
This is an example of the document i want to store: (The array index is their order)
{
items: [{itemId:xxx, otherprops...}, {itemId: yyy, otherprops...}]
}
The items collection can have 100s of items, so changing the order in that collection is not the correct option for my needs.
is it right to create a collection only to store a single document in
it
If you look at the admin database in mongodb, you'll see that it does something similar to what I think you're trying to do. There's a system.version collection. In that collection, I've seen documents that contain settings-like information. For example, the featureCompatibility property is actually stored as a document with _id: "featureCompatibility". Shard identity information is also stored as a single document in this collection:
{
"_id" : "shardIdentity",
"clusterId" : ObjectId("2bba123c6eeedcd192b19024"),
"shardName" : "shard2",
"configsvrConnectionString" : "configDbRepl/alpha.example.net:28100,beta.example.net:28100,charlie.example.net:28100" }
There is only one such document in the system.version collection. You can very well create your own settings collection where you store these bespoke documents. It's certainly not unheard of.
Take a look at the "Shard Aware" section from the official mongodb documentation to see this type of practice in action:
https://docs.mongodb.com/manual/release-notes/3.6-upgrade-sharded-cluster/#prerequisites
I am trying to understand how ExtJS associations work. I have not found an understandable tutorial on this issue that covers my main two use cases and especially how ExtJS differentiates between the two:
Association between two models through an "Id" reference.
Association between two models through a Parent-Child relationship.
I have laid the ground in this fiddle, can someone help me to fill in the gaps?
**fields: [
{name: 'AA', mapping: 'qq'},
{name: 'SS', mapping: 'pp'},
]**
The **name** you write the name given in gui part
eg:
{
xtype:'mytext',
label:'',
**name:'AA',**
editable:true
}
when you receive responses like this and in xml so the data is mapped like this:
*<wer>
<qq>data</qq>
<>data</>
</wer>*
so, we map the response data to name in gui.....
If you are using an SQL database, it's very straightforward to develop a user interface for CRUD operations. Since the schema is defined, it's obvious how many inputs you need in a form, etc.
But when using a schema-less NoSQL approach for storage, how do you build interfaces since you don't know exactly what to expect from the types of data being stored? For example if you had a database of cars:
var cars = [
{ model: "BMW", color: "Red", manufactured: 2016 },
{ model: "Mercedes", type: "Coupe", color: "Black", manufactured: “1-1-2017” }
];
If you needed to create a user interface so you could access and edit this data, you have no clue how many inputs you need since there is no schema. How do UI developers solve this problem?
Do you have a bunch of if statements to test if every possible attribute exists in the record before showing the proper inputs?
// psuedo code
if ($car.hasKey("model") ) {
// Show the "Model" input form element
}
if ($car.hasKey("type") ) {
// Show the "Type" input form element
}
if ($car.hasKey("color") ) {
// Show the "Color" input form element
}
if ($car.hasKey("manufactured") ) {
// Show the "Manufactured" input form element
}
If you needed to create a user interface so you could access and edit this data, you have no clue how many inputs you need since there is no schema. How do UI developers solve this problem?
You solve this by reasoning from feature requirements. Emphatically, you do not try to generate forms (automatically or otherwise) from schemas: that is a recipe for poor UX even if you do have a comprehensive, canonical and unequivocal schema to hand.
Instead: you know what your 'use cases' are (you ask users) and then you build exactly those.
So the question becomes:
What do you do when your data item/instance does not contain a particular object/field/key which you did expect?
What do you do when your instance contains fields which you do not know what to do with?
The answer for #1 is pretty straightforward, and basically just the same as dealing with schema changes: assume/present sane defaults or handle null values gracefully. That is: permit your users to add such fields later where they make sense and do not choke on objects that lack them.
The answer for #2 is more complicated and it is going to depend heavily on the application and its environment (for example: is it the sole consumer of the data, or are there other consumers to consider as well). One option could be normalisation: you prune such extraneous fields on saving, so objects become normalised over time as they are updated by the users. An alternative could be preservation: you keep any fields you do not know as-is, and you take pains to preserve them through every layer of your application.
I have the following store in my Sencha Touch 2.4.1 application:
Ext.define('NativeApp.store.Item', {
extend: 'Ext.data.Store',
config: {
model: 'NativeApp.model.Item',
storeId: 'item-store',
fields: ['id', 'description'],
proxy: {
type: 'ajax',
url: 'resources/json/item.json',
reader: {
type: 'json',
rootProperty: 'items'
}
},
autoLoad: true
}
});
It's being populated with everything in the JSON file, which let's say looks like this:
{
"items": [
{
"id": 's1',
'description': 'desc'
},
{
"id": 's2',
'description': 'desc'
}
]
}
Let's say that in my view I have two buttons, "s1" and "s2".
If I click on "s1", I am taken to a page with a list that contains the data with id "s1". (In this case, there is only one, but there could be more).
How would this be accomplished?
Idea 1:
The autoload attribute can be set to an Object. From here - "If the value of autoLoad is an Object, this Object will be passed to the store's load() method."
So if in my controller, in the handler that's executed when the button is tapped, I can generate this object (parse the JSON file) and somehow pass it to the store - mission accomplished. Sort of.
Besides the question of how to pass it to the store, the immediate problem is when is the data loaded into the store?
According to the docs, "this store's load method is automatically called after creation". Is creation when the app launches, or when I create the view object that uses the store:
var view = {xtype: 'myview'};
Idea 2:
Maybe I could dynamically switch out the url from the proxy and have separate JSON files for each id (there won't be too many). But that seems unlikely to work.
Idea 3:
Pass in a data object to the store (again parsing the JSON) from that controller.
Are any of these feasible? And if not, what is an alternative solution?Perhaps I'm overthinking this.
Edit:
I have a list of items, and each item has a list of sub-items. So when I select one item, I want to be taken to page of the sub-items. Right now, all of these sub-items are in one JSON file, so after clicking on one item, I need a way of telling the store to load only part of the json data.
Is Ext.data.model.load still the best approach?
Idea 1:
Yes, you could do that... probably more trouble than it's worth IMO. The store will load immediately after it is created -- so if you create the store at application start, then it loads then. If you create a store randomly during runtime, it loads then. If the store is defined inline for a view, it's loaded when the view is created.
Idea 2:
Arguably a better solution, but still a lot of trouble to swap the URL for the proxy, then forcibly load it, parse the data, etc.
Depending on your view, you could just directly load the data for a single model using NativeApp.model.Item.load(id) (see docs). This assumes you have an API setup for that, but it's easier IMO and certainly more RESTful.
Idea 3:
Meh. It really sounds to me like Ext.data.Store is the wrong construct for what you're trying to accomplish.
Are any of your ideas feasible? Yes.
Are you over-thinking this? Slightly, but then again you wouldn't be a programmer if you didn't.
It's hard to tell you exactly what I'd do without seeing the rest of your application and understanding the WHY you're doing X, Y, or Z... but if you're only planning on displaying a single model's data on a given "Detail" screen (and you need that data loaded on-demand), then the static Ext.data.Model.load() method is probably what you need.
Let me explain my situation:
I have model with array field inside it
Ext.define('MyModel',{
extend: 'Ext.data.Model',
fields: [
{ name: 'myfield', type: 'array' }
]
})
that contents data like this
data = Ext.create('MyModel',{
myfield: [ 'one', 'two', 'three', 'four' ]
})
I want to extend Ext.form.field.Base to create field that treats this array as todo-list and contains items inside itself ( Ext.form.field.Trigger to add "todo" and Ext.ListView to display "todo's" ).
I don't know how difficult it is to make Ext.form.field.Base contain items and are there any better possible solutions.
Field must get array on loadRecord() and give it on getRecord() of Form.
Other possible solutions I see:
1) Make Field only with html-template and vanilla-javascript ( bad because why to implement things that are already present in ExtJS )
2) Model relations ( bad because I have to implement 'create, update and delete' for each related model and load them manually )
Thank you for reading, any ideas are welcome!
Not related directly to your question, but "array" is not a valid field type for a Ext.data.Field. Use 'auto' for no data conversion, or just don't assign a type.
Re: the custom, complex form field, it's certainly possible with ExtJS, and creating an extension of the Trigger field is definitely what you'll want to do. Here's an example of a custom trigger field that handles complex data: http://existdissolve.com/2012/12/extjs-4-custom-editor-for-property-grid/. The example is for a custom property grid, but the principle is the same for any custom form field.
The most important parts in your custom field are going to be the implementation of the createPicker() method and whatever mechanism you define for setting the value of the underlying field.
Hope this gives you a good place to start.