I'm new to Dojo, and I'm trying to get my head wrapped around some pretty basic concepts before my partner and I embark on a new project. I've been successful in using the ItemFileWriteStore to get data returned from an ajax request into a DataGrid, but I would like to use the new Memory store instead. I am using the ObjectStore adapter to wrap the Memory store, and data is being populated in the grid.
One thing has me worried. In the example code I'm running, there is some nested nodes in the JSON object I'm using to populate the grid. It's one of the Countries JSON object they use in the dojo documentation. Here's a little snippet of that object:
'items': [
{ 'name':'Africa', 'type':'continent', children:[
{ 'name':'Egypt', 'type':'country' },
{ 'name':'Kenya', 'type':'country', children:[
{ 'name':'Nairobi', 'type':'city' },
{ 'name':'Mombasa', 'type':'city' } ]
},
{ 'name':'Sudan', 'type':'country', 'children':
{ 'name':'Khartoum', 'type':'city' }
} ]
},
]
In the DataGrid instantiation, I send in a query and then I set the qureyOptions to {deep:true} like so:
var grid = new DataGrid({
style: "width: 500px; height: 300px;",
store: this._geoStore,
structure: layoutGeo,
rowSelector: '20px',
columnReordering: true,
query: {},
queryOptions: { deep: true },
rowsPerPage: 20
}, document.createElement("div"));
When I use the old ItemFileWriteStore, this works fine, and ALL the nested data is essentially flattened out and placed in the grid as I would expect. However, when I switch it over to a Memory store wrapped in an ObjectStore adapter, the only data displayed in the grid is the top most parent of the data object. In the case of the sample data, only the data associated with Africa, but none of its children, are displayed. So it seems that the queryOptions {deep:true} statement has no affect when using the Memory store.
Is there some way of getting nested data within the JSON objects into a data grid using a Memory store wrapped in an ObjectStore? I would have thought that the wrapper class would have taken care of this, and it might, but I don't know how to fix it.
For all who help, thank you very much for your time and willingness to share your expertise. I really have studied the dojo docs and web for a long time trying to figure this stuff out. I fear I may have glossed over something obvious and am hoping you all can help.
I blogged about the store changes at http://swingingcode.blogspot.com/2012/03/dojo-implementing-viewmodelstore.html
The code here uses the new store object but brings the reference notation from the data api. All objects would be considered top level objects and query-able. I did not implement the logic to pull out nested objects.
Related
Hello good people of the stack!
I am working on a react-redux application and I am trying to update a property on a deeply nested structure in my reducer. The data structure is as follows and I want to update the text property:
state = {
assessment: {
requirements: [
questions: [
{
text
}
]
]
}
}
so I have tried the following:
// reducer code...
return {
...state,
[assessmentId]: {
...state[assessmentId],
requirements: [
...state[assessmentId].requirements,
[requirementId]: [
...state[assessmentId].requirements[requirementsId],
questions: [
...state[assessmentId].requirements[requirementsId].questions,
[questionId]: {
text: action.payload.response.text
},
],
] ,
],
},
};
This is more pseudo code than actual code to remove complexity.
I do not see any change in redux dev tools so I am wondering if I have made a mistake the way I get the nested objects and array elements.
I was also curious about using combine reducers here. I asked a colleague and they suggested to use that but I am unsure how you would take that approach here. As always, any help is appreciated.
I recommend immer for deep state changes in your reducers.
It adds a little weight to your bundle, and you'll get better performance from using the spread operator, but if you can live with that it'll make your code easier to read and write.
import produce from "immer";
// reducer code...
return produce(state, draft => {
draft[assessmentId].requirements[requirementsId].questions[questionsIndex].text = action.payload.response.text;
});
I'd say your issue stems from questions being an array which will take a little more work to keep straight than object based state.
As it is you appear to be trying to set the question value as if questions was an object. Maybe you just need to drop the [questionId] syntax, eg
questions: [
...state[assessmentId].requirements[requirementsId].questions,
{ text: action.payload.response.text },
],
This will set the text object as a new item on the end of the array though.
Depending on what you need to do (ie what already exists in the array and whether you are trying to add or update) you'll want to have a read of:
https://redux.js.org/recipes/structuring-reducers/immutable-update-patterns#inserting-and-removing-items-in-arrays
https://redux.js.org/recipes/structuring-reducers/immutable-update-patterns#updating-an-item-in-an-array
I need help designing a simple app which allows user to rate videos using a form. My state is composed by 2 reducers, one that holds data about all ratable videos (in a normalized fashion) and another one that holds the form state:
{
videos: {
'video1Id': { id: 'video1Id', title: 'Cat video', duration: 120, ... },
'video2Id': { ... },
...
},
rateForm: {
'videoId': 'video1Id'
'userComment: 'A nice video about cat'
'formSubmitted': false
...
}
}
Note that, inside rateForm, I reference the video id instead of the video object. Problem is, how can I retreive the whole video object from my rateForm reducer ?
I feel like I'm following the best practice of Redux design but I'm stuck at this really simple use case. Any help appreciated.
Thanks
One thing to remember, reducer should be AS SIMPLE AS POSSIBLE. Only doing atomic operations on reducer level. From what I can tell you trying to retrieve the whole video object in your reducer just doesn't sound right.
Depending on your needs, usually, you don't need to fetch the whole video object if you just want to comment on it or rate it. But if you are 100% sure you have to, A good place to do this is in your action. Using Redux-Thunk, you will have access to the whole state object before you return your thunk. Example
function doSomethingToVideo (videoId, something) {
return (dispatch, getState) => {
const video = getState().videos[videoId]
// Do what ever
return somethingElse
}
}
Reference: Redux author's answer on a similar matter.
Accessing Redux state in an action creator?
I'm using normalizr to flatten a structure like the following one:
{
"fields":[{
"id":"29",
"text": "something"
}, {
"id":"16",
"text": "something"
"fields":[{
"id":"17",
"text": "something"
}]
}, {
"id":"18",
"text": "something"
}
}
My structure has an array of fields and a field may also have nested fields. There's only one level of nesting allowed.
What I'm trying to do is this:
const block = new schema.Entity('fields')
const blockList = new schema.Array(block)
block.define({
fields: blockList
})
const normalizedData = normalize(originalData, blockList)
After running this snippet, normalizedData has a results property and it only has the first level of field ids, even though entities has all the fields normalized, including the nested ones.
I'd like to have in the results array all the ids, including the nested ones. What am I missing?
I'd like to have in the results array all the ids, including the nested ones. What am I missing?
This is how Normalizr works. The returned result is always in the same format of the input data. You won't be able to get what you are asking for from Normalizr.
If, however, you're just looking for a list of blocks, pull that from the entities:
const blockIds = Object.keys(normalizedData.entities.blocks);
You should consider using a normalized form for your data structure in redux.
This is advisable if your application need growth in complexity.
There is an interesting article on redux docs.
http://redux.js.org/docs/recipes/reducers/NormalizingStateShape.html
A normalized form take some ideas from db counterpart and Normalizr works in that way, so your request does not really match with how Normalizr works.
Please consider #Paul Armstrong answer for a work around if you really need get blocks in that way.
I am currently developping an app with the amazing Meteor platform. I would like to do something with my collections but I couldn't really find how to do it from the examples I have seen so far.
Basically I would like to display a list of items which contains their own countdown. Each items core data come from a collection. Each countdown starting times must be computed server side and not saved anywhere. Each countdown are computed client side and not saved anywhere.
I have a collection named "items" coming from my MongoDb db. At the beginning document in my collections could look like:
{ name: "My countdown"}
1) I would like to "extend" the documents server side in adding a computed property "startTime". A documents could look like then:
{ name: "My countdown", startTime: 40 }
I guess I need to use the publish method, but I don't really get how to extend existing documents that way.
2) I would like to "extend" the documents client side in adding a local property "currentTime", that i will update with a setInterval. A document could look like then:
{ name: "My countdown", startTime: 40, currentTime: 5 }
Maybe using a transform there but once again I don't really get how to extend existing documents.
3) I would likethoses 2 new properties reactives and so trigger some updates in the UI if they change.
So if i could get any starting points and good pratices it will be really appreciated :)
Many thanks for your help!!
You can update a document of a Collection: Best practice is to do this on the server.
client.js
Meteor.call('setStartTime',
[your_document_id],
[new_start_time],
function(err, val) {
if (err) {
console.error(err);
} else {
// Successful.
}
});
server.js
Meteor.methods({
'setStartTime': function(itemId, newStartTime) {
Items.update(itemId, {
$set: { startTime: newStartTime }
});
}
});
This will set or update the startTime of your item. (Be cautious, as anyone with access to your JavaScript will be able to see your setStartTime call on the client. This is functional, but not secure.)
Copying the rows from the grid and inserting into same grid in begining (insert at position 0).
It was causing performance issue, as soon as hits more than 10 rows. I started using
store.suspendEvents(true);
foreach(..)
{
r = ...
store.insert(0, r);
}
store.resumeEvents();
It improves a performance, as grid is no longer getting refresh with each insert of row in the store. however for some reason it throws exception while indexing the rows in the store. I think because store events are suspended, its going in some bad state.
fyi. its adding second row in the last again, where it throws with exception message.
Any other suggestion on how to handle this situation in any other way is welcome.
You should create a store and then have the grid use that store. You can then manage the store as needed and the data will automatically be available to the grid. Something like:
var the_store = Ext.create('My.store.Foo', {
extend: 'Ext.data.Store',
fields: ['id','name'],
...
proxy: {
...
}
});
var the_grid = Ext.create('My.view.Grid', {
extend: 'Ext.grid.Panel',
...
store: the_store,
...
});