Can’t update existing view with each-in helper - ember.js

We are creating a Sportsbook web app using Emberjs, where we retrieve data through an API and draw the view.
The received data is an object with many nested levels. Based on this object we have constructed the template file(.hbs) using each-in helper!
We are unable to use 'each' helper as we are receiving object, not array!
After the first retrieval, we are receiving updates every milliseconds and need to update the view as well by changing only the difference.
Sometimes we are receiving new entries in the object, and as the object itself is big, we need to add the new entry to the layout without redrawing the whole stuff.
Here is the problem: Each-in is not observable in this case, so it is not redrawing after pushing the new object.
Question: Is there a good way to implement this with Ember or is there a known helper that we can use instead of each-in, OR is there someone who can recommend me if we CAN create a new helper for this?

Related

How to refresh model data from inside component in EmberJS?

Currently I have a set up a application that lists the model collection and also have implemented pagination in it.
Now, I want to move all of this logic into a component so that it is reusable across multiple listings. To achieve this, I have passed the model variable inside the component.
Since, server data communication is considered a bad practice I assume the changes must be applied to the controller ?
So, I am confused on how to make the api call to refresh the data can be called ?
You can build method in controller and pass them as method in the required components. This way, you can avoid data call in component and make it reusable.
eg:
{{some-list getData=getSomeListData}}
where getSomeListData applies the required data changes.

Do I need to redesign my application?

I may be bordering on a discussion type question here so I apologise if the question is not specific enough.
I would like to know if I my current application design is inherently weak/flawed. My background is C so I am not using clever c++ patterns to their fullest extent, of this I am sure.
My application is similar to a 3D modelling package, without geometry creation (e.g setting up animations using existing models). The user imports a geometry and can set various parameters on pre existing geometry, and there are time dependent values that relate to the whole system. The output is a text file to be processed by another application.
I am using a QTreeview to render a QStandardItemModel. I simply store pointers to my core classes in the model's items. These have specific UI for each class type, and are all descended from a common base class. They all have a QWidget which is their "mainwidget"
When the user clicks on part of the treeview, the stored class is retrieved and its mainwidget is displayed on a pane on the UI. So - treeview on the left, pane to the right with the current item's contents, and a 3D view showing the geometry.
Most of my data is stored in the classes UI elements themselves; I don't have a central database which stores anything, and when it's time to save the project, I traverse the tree and let every item write itself to a QSettings file. This feels quite naive but it does work, and the reverse happens on project load. The project class generates new classes based on the type information in the settings file and they then read the contents out of the file themselves.
Similarly when writing the output file, each item knows how to write itself and does so. Where other classes can influence the output of others (for example, start and end times), higher level classes process the children and will set start and end times based on the order and duration of each child.
Should I be storing more data in the QStandardItemModel itself, or defining my own model perhaps? Does it sound like I have set myself up for future problems?
At the moment I have modified this system a couple of times to provide customised applications, but I am about to try and make it more generic. I welcome suggestions for improving my design. Go easy, please!
You should try to avoid creating god objects. Split your tasks and duties into smaller chunks. It makes it much easier to maintain and also much easier to extend if you need to.
Your specific use-case would benefit a lot from a more complete use of the Model-View-Controller pattern.
What doesn't make sense in your design is that your data objects hold a UI element. Since only one item can be shown in the right pane, this seems like a waste of resources. It makes more sense to have a single object that then gets passed a data object to display.
What I suggest for your program is the following:
Splitting your data into classes that only have functions for reporting and modifying values. There should be no knowledge of how to display data or store to a file.
Create separate class that handles the reading and writing from a file. If your model is very simple, you could just use single functions to do this using the method shown in the documentation for QDataStream or QTextStream.
Use your QTreeView and QStandardItemModel as Adaptor class between your data objects and the left pannel.
Create a controller class that gets informed by the QTreeView if data needs to be displayed in the right panel. The controller will then retrieve the data item and pass it to the right panel in order to be displayed.
The right panel should act like another View class with the sole responsibility of graphically displaying the data passed in from the controller class.
One advantage of doing it this way is that, if there are different categories of data that get displayed differently in the right panel, the controller could examine the selected data item, determine what the category is, create a view widget to put in the right panel, and then pass it the data to display.
This pattern is open-ended as far as extendability is concerned because you do not need to change your data classes if you need a new display, you merely need to create a new right-panel widget, and then teach your controller class how to determine when the new view should be used.
Another advantage of this pattern is that you only ever need to have a single widget created to display data in your right panel. If you change your selected item, you can just pass it to the view class that already exists and get it to refresh its display with the newly selected data. You only need to distroy the right-panel view widget if a different category of data object is selected and its data needs to be drawn in a different way. The controller class can determine whether a right-panel view widget can be re-used or whether it needs to be swapped out for a different widget.

Qt 5.2 Model-View-Pattern: How to inform model object about changes in underlying data structure

I have a class used for permanent storage of some item that are organized in a table-like manner. This class is totally unrelated to Qt and comes from a different library. Lets call this class DataContainer for the rest of this question. It provides std-c++ compatible iterators to access and manipulate the content.
I need to display and modify that data through a Qt GUI. My idea was to create a class DataContainerQtAdaptor that inherits from QAbstractTableModel and stores a pointer to the DataContainer object. The DataContainerQtAdaptor serves as an adaptor to the DataContainer object and all manipulation from inside of my Qt app is done through this adaptor. Then I use a QTableView widget to display the information.
Unfortunately the DataContainer might be changed by threads/processes. (For example think of DataContainer as some C++ class that encapsulates a database connection and that database might be changed by someone else.)
Questions:
1) Assume I have a function that is called everytime the internal structur of the DataContainer object has been changed. What is the correct function of the QAbstractTableModel that must be called to inform the model of the underlying change? I need something like "Dear Model, your persistent storage backend changed. Please, update yourself and emit a signal to every attached view in order to reflect this change".
2) Lets say 1) is solved. What is the best way to avoid a "double" GUI update in case the change was triggered through the GUI? E.g: User clicks on a cell in the table widget -> table widget calls setData of the model -> model pushes change to backend -> backend triggers its own "onUpdate" function -> model re-reads complete backend (although it already knows the change) -> GUI is updated a second time
3) The user should be able to insert new rows/columns through the GUI and put data into it. But the position is detemined by this data, because the backend keeps the data sorted. Hence, I have the following problem: The user decides to create a new row at the end and the new data is pushed to the backend. When the backend/model is re-read this data is normally not at the last position, but has been inserted somewhere in the middle and all other data has been moved forward. Ho do I keep all the properties of the the table view widget like "selection of a cell" in sync?
I believe, there must be some simple standard solution to all these question, because it is the same way as QFileSystemModel works. The user selects a file and some other process creates a new file. The new file is displayed in the view and all subsequent rows move forward. The selection moves forward, too.
Matthias
Model Semantics
First of all, you must ensure that the QAbstractItemModel cannot be in an inconsistent state. This means that there are some signals that must be fired on the model before certain changes to the underlying data are done.
There is a fundamental difference between changes to structure and changes to data. Structure changes are the rows/columns of the model being added or removed. Data changes affect the value of existing data items only.
Structural changes require calling beginXxx and endXxx around the modification. You cannot modify any structure before calling beginXxx. When you're done changing the structure, call endXxx. Xxx is one of: InsertColumns, MoveColumns, RemoveColumns, InsertRows, MoveRows, RemoveRows, ResetModel.
If the changes affect many discontiguous rows/columns, it's cheaper to indicate a model reset - but be wary that selections on the views might not survive it.
Data changes that keep the structure intact merely require that dataChanged is sent after the underlying data was modified. This means that there is a window of time when a call to data might return a new value before dataChanged is received by the object that queries the model.
This also implies that non-constant models are almost useless from non-QObject classes, unless of course you implement bridge functionality using observer or similar patterns.
Breaking Update Loops
The Qt-idiomatic way of dealing with update loops on the model is by leveraging the item roles. It's entirely up to you how your model interprets the roles. A simple and useful behavior implemented by QStringListModel is simply to forward the role from the setData call to dataChanged, otherwise ignoring the role.
The stock view widgets react only to dataChanged with the DisplayRole. Yet, when they edit the data, they call setData with the EditRole. This breaks the loop. The approach is applicable both to view widgets and to Qt Quick view items.
Insertion of Data into Sorted Models
As long as the model properly emits the change signals when the sorting is done, you'll be fine.
The sequence of operations is:
The view adds a row and calls model's insertRow method. The model can either add this empty row to the underlying container or not. The key is that the empty row index must be kept for now.
The editing starts on an item in the row. The view state changes to Editing.
Editing is done on the item. The view exits the editing state, and sets the data on the model.
The model determines the final position of the item, based on its contents.
The model invokes beginMoveRows.
The model changes the container by inserting the item at the correct location.
The model invokes endMoveRows.
At this point, everything is as you expect it to be. The views can automatically follow the moved item if it was focused prior to being moved. The edited items are focused by default, so that works fine.
Required Container Functionality
Your DataContainer doesn't have enough functionality to make it work unless all access to it were to be done through the model. If you want to access the container directly, either make the container explicitly inherit QAbstractXxxxModel, or you'll have to add a notification system to the container. The former is an easier option.
Your core question reduces to: can I have model functionality without implementing some variant of the model notification API. The obvious answer is: no, sorry, you can't - by definition. Either the functionality is there, or it isn't. You can implement the notification API using an observer pattern if you don't want the container to be a QObject - then you'll need your model shim class. There's really no way around it.
The QFileSystemModel gets notified by the filesystem about individual directory entries that have changed. Your container has to do the same - and this amounts to providing a dataChanged signal, in some shape or form. If the model has items that get moved around or added/removed - its structure changes - it has to emit the xxxAboutToBeYyy and xxxYyy signals, by calling the relevant beginZzz and endZzz methods.
Indices
The most important underdocumented aspect of QModelIndex is: its instances are only valid for as long as the model's structure hasn't changed. If your model is passed an index that was generated prior to a structure change, you're free to behave in an undefined way (crash, launch a nuclear strike, whatever).
The whole reason for the existence of QModelIndex::internalPointer() is your use case of having an underlying, complex-indexed data container. Your implementation of the model's createIndex method must generate index instances that store references to the DataContainer's indices in some form. If those indices fit in a pointer, you don't need to allocate the data on the heap. If you need to allocate the container index storage on the heap, you must retain a pointer to this data and delete it any time the container's structure changes. You're free to do it, since nobody is supposed to use the index instance after a structure change.
From the documentation of method bool QAbstractItemModel::insertRows(int row, int count, const QModelIndex & parent = QModelIndex()):
If you implement your own model, you can reimplement this function if
you want to support insertions. Alternatively, you can provide your
own API for altering the data. In either case, you will need to call
beginInsertRows() and endInsertRows() to notify other components that
the model has changed.
The same goes for removeRows() and moveRows() (they have their own begin*() and end*() methods). For modifying data of existing item there's a dataChanged() signal.
Here's how it goes (answer for question 1):
Implement your own methods for inserting/deleting/modifying data, where each of those methods must look like this:
beginInsertRows(parentIndex, beginRow, endRow);
// code that modifies underlying data
endInsertRows();
beginRow and endRow must be provided to inform which where the rows will be inserted and how many of them (endRow-beginRow).
For beginDeleteRows() and beginMoveRows() it's the same.
When you have a method which simply modified data in existing item, then this method must emit signal at the end: dataChanged().
If you do a lot of changes in the data, it sometimes is simpler to just call beginResetModel() and endResetModel() in the method performing this huge modification. It will cause all views to refresh all data in it.
Answer for question 2:
This is up to the View class implementation if it will "double-update". When you enter data in the View, data is sent to the model through one of the edition methods in model (insertRows(), setData(), etc). Default implementation of those methods always use begin*() and end*() methods and so the proper notification signals are emitted by the model. All Views listen to those signals, including the one you used for entering the data, therefore the "double-update" will be performed.
The only way to define this behaviour is to inherit the View and reimplement its protected slots (like dataChanged() and similar) to avoid updating if the value was detected to be provided by this view.
I'm not sure if Qt views do that already or not. Answer to this requires someone more educated in Qt internals, or looking into Qt source code (which I don't have at the moment). If somebody knows this, please comment and I will update the answer.
I think it's not that bad to reload the data from model - it guarantees that what you see is indeed the value from the model. You avoid possible problems with the Editor and the View bugs.
Answer for question 3:
When you reload whole model, then there is no simple way to keep track of selection. In that case you need to ask view->selectionModel() about current selection and try to restore it after reload.
However if you do partial refreshing (using methods I described in answer 1), then the View will track the selection for you. Nothing to worry about.
Final comments:
If you want to edit data from outside of model class, you can do it. Just expose begin*() and end*() methods as public API, so other code that edits data can notify model and views about changes.
While it can be done, it's not a good practice. It may lead to bugs, because it's easy to forget about calling notification everywhere you modify the data. If you have to call model API to notify about changes, why not already move all editing code insise the model and expose editing API?

Ember Custom View Creating a Chart View

Im in the process of creating a view for a chart with jquery.flot. So I created a view and in my template call it like so:
{{view GraphView graphableBinding="graphables"}}
Problem is the graphables object is an array and the observers do not fire which notifies me of changes to the array within the view.
I thought about using a CollectionView, however, the array itself doesnt affect the html result of the template but rather needs to fire a $.plot() command on the container div with the new data array. Any thoughts on how I would implement this sort of thing?
You can use #each key lets you observe changes to the contents of the array. See the ember.js guide regarding this feature:
http://emberjs.com/guides/object-model/computed-properties-and-aggregate-data/

Emberjs Handlebars #each helper slow when bound to computed properties

I'm running into a performance issue when I render a list of items using the #each helper or a collection view bound to some computed properties of an Ember.ArrayController. Performance is fine with a small list of 10 - 20 items, but around 50 - 100 it starts to lag quite noticeably. Try checking off a few todos or clicking "Add Todo"
Example code is here: http://jsfiddle.net/Jonesy/ed3ZS/4/
I noticed that the childViews in the DOM get re-rendered with each change, which could very well be the intended behaviour at the moment, but I'd prefer to be able to just have a todo be removed from the DOM of unfinished todos list individually and appended to the bottom of the finished todos list, which would in theory be much less costly.
What I'm hoping to have answered is whether am I looking at a performance issue with Ember collection views, or is displaying a list populated from a computed property a bad idea, and if so, will I need to manually manage the todo model's location in the view layer as it changes from unfinished to finished and vice versa.
This is a side-effect of how {{#each}} (and CollectionView, which is what powers it) works.
Internally, CollectionView uses something called array observers. An array observer allows you to subscribe to mutations made to an array when they are done using Ember.Array's mutation methods (replace, pushObject, popObject, etc.) The API for array observers is described here.
What this means is that, if you push a new object into a collection view, it will insert render one new element in the DOM and leave the rest in place.
In the example you posted, however, the array is not being mutated--you're creating a brand new Array object every time a new item is added or removed. When the binding synchronizes, it replaces the old array with the new array. To {{#each}}, this is no different than removing all of the elements and then adding them back in.
The solution to the problem is to use a single array, instead of a computed property that returns a different array object each time it changes. You can see the Contacts app for an example of how to do this.
Obviously this is a very common pattern, and we'd like to add some kind of filtering that does the right thing by default to Ember.ArrayController down the road.