Bear with me as I am coming from a traditional web development background, using ASP.Net, and even server side MVC. I am attempting to build a highly interactive single-page application using Backbone.js to help organize my javascript code and build the UI.
I am having trouble with some concepts, or approaches to building the components of my UI, and deciding how to handle certain aspects. I am going to use this oversimplified screen shot as a basis for my questions and discussion.
Let's use a "TO-DO" application as an example (of course.) The UI is pretty simple. I have the following "components"...
A results list which shows the current set of to-dos that match the currently selected criteria
A list of my to-do lists (Personal, Work, Blog Project)
A list of due date filters (Today, Tomorrow, This Week, Next Week)
A list of tags (Bug, Feature, Idea, Follow Up)
A search box
Desired Functionality
Update the results whenever any of the search criteria changes (choose a list, choose a due data, choose one or more tags, enter search text, etc.)
The user can edit, add, and delete lists. (not really shown in this mock up)
The user can edit, add, and delete tags. (not really shown in this mock up)
The user can edit, add, and delete to-do items. (not really shown in this mock up)
Data Models
There are several models that I identified that are "data" related. These were easy to identify.
ToDo (represents a single to-do item)
ToDoCollection (represents a collection of to-do items)
ToDoList (represents a single to-do list)
ToDoListCollection (represents a collection of to-do lists)
Tag (represents a single tag)
TagCollection (represents a collection of tags)
How to Store UI State?
This is where I am having trouble. I want to show which items in my menus (on the left side) are currently selected. I can certainly listen for events and add a "selected" class to items as they are selected, but I also have rules, like "only one list can be selected at a time", but "any number of tags" can be selected at a time. Also, because the To-Do List menu and the tags menu are dynamic, they already are associated with a ToDoListCollection and TagCollection models already. They are rendered according to the state of these "data models".
So, how do I handle the management of this UI state for all these different views using Backbone? I appreciate any ideas or suggestions.
Thanks!
I had exactly the question you did, and I'll let you know the secret: cheat.
What you have here is two different application layers, and some confusion about them. The first layer is the relationship between to-do objects in your system. These, you store in a traditional object relational model, and you create/retrieve/update/delete them as you would any other RESTful application.
The second layer is the relationship between your display of these objects, and the objects themselves. There's some state there you want to preserve. Here's the important insight: as long as every object GET, PUT, or POSTED to the system has a unique ID, the second layer can be completely independent of the first.
The first layer is a RESTful API to "a to-do manager." The second is something unique to this presentation. It's relationship to data in the first is tenuous. So here's what I did: I encoded that presentation layer state into a JSON object and wrote it to an 8-bit clean text field in the user's profile. Every time the user changes state, I do that.
When the app loads, it loads the bulk of the data from the REST API and the presentation layer information, discards any in the presentation layer that doesn't make sense, and then starts Backbone.History and initializes the presentation. And the server doesn't need to know any details at all about how the client works. As long as the client speaks your RESTful lingo, it can save "miscellaneous things this particular client cares about" to that text field without affecting your objects or their relationship.
Related
I am developing a website in React.
In this website I have a screen - lets call it "book-an-appointment"
And I have multiple flows:
book an appointment for existing client
book an appointment for non-existing client
book-an-appointment is part of flow 1 and 2, with slight differences:
some buttons that are shown only in one of them
"next" button that takes the user to a different screen
it affects differently on the funnels
of course each one of them is in a different URL
and more...
Question: Which approach is best practice in developing such screen in react?
options I thought about are:
Creating A single screen that shows the relevant buttons and actions according to the state
Duplicating the screen for each flow (because of the small differences in it)
I am quite new to react. tried to look for an answer here and in google but couldnt find my answer.
In that case I would just use one Parent component with ether two child components with the different flows. You can make one JSON object where conditionally you add specific keys and you can later check if the isExisting field exists for example what kind of booking it is and show a the existing user flow component.
You could do it like that or have one component that just conditionally hides fields depending on what type of booking it is. In this case you would use conditional rendering. See the article below for more info.
https://reactjs.org/docs/conditional-rendering.html#inline-if-with-logical--operator
We have a WPF desktop application that uses MVVM pattern and DDD (well, let's say that at least my model classes that store data named by entities taken from the real world). APP uses several microservices through REST API. And it worked perfectly. Until we thought that it's time to use some facade for back-end part to unite all those microservices and get only data that we need for particular screen.
BUT. The question is, how to make them live together.
On the one hand, we have dynamically returned data from graphql. It
means that, for example, if we have list of people on the one screen,
we will request id, name, surname and role of the person. On the
different screen for dropdown of people we will request the same data
but without role.
On the other hand we have class Person that has static set of fields Name, Surname, Role and Id, which person has in "real life"
If we use the same Person class with graphql, converting data from JSON to model Person, both screens will work fine, but behind the scene one screen that doesn't need Role wouldn't request it from graphQL. And we will have a situation when model class Person will have field Role but it will be just empty (which is i believe is kind of smells. At least I don't feel like it would be easy to maintain such a code. Developer needs to add some information to the screen, opens model, sees that Role is there, bind the field to the screen and goes to drink cofee. And then oops, there is the fields but there was no data assigned ).
Two variants I have on my mind are:
either to not use models and DDD and map data directly to ViewModel
(which personally feels like ruining everything we had before).
or we map that dynamic data to our existing models and different field for different screens (for the same class Person e.g.) will be
empty (because not requested).
Maybe somebody has already used such a combination. How do you use it and what pros and cons are?
It's a fairly common situation where you have a data layer returns many columns but only some are used in a given view.
There is no absolute "best" solution independent of how much impact the full set of columns will have on performance. Which might in turn be linked to things like caching.
You could write services that return subsets of data and then you only use the necessary bandwidth. Sort of a CQRS pattern but with maybe more models than just read + write.
Often this is unnecessary and the complications introduced do not compensate for the increased cost of maintenance.
What is often done is just to map from model to viewmodel (and back). The viewmodel that needs just 4 columns just has 4 properties and any more returned by the model are not copied. The viewmodel that needs 5 has 5 properties and they are copied from the model.
Many examples on the net show you how to use ng-repeat with in-memory data, but in my case I have long table with infinite scroll that gets data by sending requests to a REST API (scroll down - fetch some data, scroll down again - fetch some more data, etc.). It does work, but I'm wondering how can I integrate that with filters?
Right now I have to call a specific method of API service that makes a request based on text in "search" input box and then controller updates $scope.data.
Is it possible to build a custom filter that would do that? And then my view would be utterly decoupled from the service and I could declaratively tell it how to group and order and filter data, regardless if it's in-memory or comes from a remote server, server that can serve only limited records at a time.
Also later I'm gonna need grouping and ordering as well, I'm so tempted to download the entire dataset and lock parts of the app responsible for grouping, searching and ordering (until all data is on the client), but:
a) that dataset is huge (hundred thousands of records)
b) nobody wants to deal with cache invalidation headaches
c) doing so feels so damn wrong, you don't really expect me to 'keep' all that data in-memory, right?
Can you guys point me to maybe some open-source examples where I can steal some ideas from?
Basically I need to build a service and filters that let me to work with my "pageable" data that comes from api, like it's in memory-data.
Regardless of how you choose to solve it (there are many ways to infinite-scroll with angular, here is one: http://binarymuse.github.io/ngInfiniteScroll/), at its latest current beta version, ng-repeat works really bad with large amount of data - so do filters. The reason is obvious - pulling so much information for changes is a tuff job. Moreover, ng-repeat by default will re-draw your complete list every time something changes.
There are many solutions you can explore in this area, here are the ones I found productive:
http://kamilkp.github.io/angular-vs-repeat/#?tab=8
http://www.williambrownstreet.net/blog/2013/07/angularjs-my-solution-to-the-ng-repeat-performance-problem/
https://github.com/allaud/quick-ng-repeat
You should also consider the following, which really helps with large amounts of data.
https://github.com/Pasvaz/bindonce
Updated
I guess you can't really control your server output, because filtering and ordering large amount of data are better off done on the server side.
I was pointing out the links above since even if you write your own filters (and order-bys), which is quite simple to do - http://jsfiddle.net/gdefpfqL/ - (filter by some company name and then click the "Add More" button - to add more items). ordering by is virtually impossible if you can't control the data coming for the server - the only option is getting it all, ordering and then lazy load from the client's memory. So if each of your list items doesn't have many binding by it self (as in the example I've added) - the list item is a fairly simple one (for instance: you simply present the results as a plain text in a <li>{{item.name}}</li> then angular ng-repeat might work for you. In this case, filters will work as expected - say you filter by searched text:
<li ng-repeat="item in items | filter:searchedText"></li>
even for new items added after the user has searched a text, it will still works because the magic of binding.
I am just beginning to use backbone.js for a new crash project. My app has a dynamic (data-driven) user menu. Each menu option is a set of graphs/small tables, of mixed types. For example, a Sales Overview menu option can have a page with 2 pie chart objects, 2 line charts, a bar chart, and so on. I don't know up front what the menu options are going to be, nor what each menu option will entail.
I am considering defining a bunch of generic model "classes" by extending Backbone.Model - PieModel, BarModel, DispersionModel, etc. And corresponding View classes that can render an object of a type - PieView, LineView, and so on. Then I can assemble a page by putting these together as defined by the dynamic configuration. Each model instance's data url can be easily generated on the fly, via the dynamic configuration..
My first concern was if Backbone supports a Collection of mixed Model types. This is instigated by presence of a "model" property for a Collection - does it assume homogeneity? But it also says a collection can hold an ordered set of models.... model attribute can be polymorphic... a method to get "models" held in the collection. Should I be reading this as "model objects"?
A "page" to me really is a collection of such objects. I would like to create a Collection on the fly and populate it with instances of different model types. And then render this through a View. Or, create a View with an array of various model objects and render the View, bypassing the Collection all together.
I will appreciate your inputs on the design I have outlined, and good reference on backbone, and clarity on how to deploy a Collection in mixed model cases? Perhaps there is a different, smarter way to handle such scenarios...
Thanks.
Collections only really use their model attribute when passing plain objects into its adder functions (e.g. add, push). If you take a look at the source, each adder function passes the input through _prepareModel, which checks if the input is an instance of a Backbone.Model. If it's not, it tries to instantiate a new model using the collection's model, otherwise it just returns the input untouched.
So as long as you're always adding real Model objects to your collections you should be fine using different types.
However, if you're planning to use aggregate functions that act on model attributes (e.g. pluck) you may run into errors when the function tries to get at an attribute that doesn't exist in one type of model (though most of the time I think it would just silently fail, which might be what you want).
I am not sure if I have 100% properly understood your scenario, however, I am not convinced you are thinking about this in the right way...
In my opinion, your models should contain the data, and views should represent them. As such, in a sales context you might have a SalesData model which could be displayed in PieView, BarView or TableView. Try to completely separate display logic from data - the type of chart falls under display logic in my opinion.
With the above approach, each page would then contain a set of different views, which you could potentially contain in a master view if you felt the need. Each view would have its own model (or collection depending on how you structure the data), which you can then update/manipulate using the normal Backbone methods.
As far as I know it is not possible for a collection to have different types of models contained within it, but even if it was, I would probably not recommend it as it would complicate the code a lot.
In terms of learning resources, here are a couple:
Learn Backbone JS compeltely -- javascriptissexy.com - this one is very thorough but will take some time to get through.
Backbone patterns - much quicker to get you in the right frame of mind.
Lets take an example of WinForms applcation and making invoice. On the Invoice form we retrieve a list of products, so the user will be ale to pick products for current invoice. Lets also consider that during this process user realizes that he needs to add a new product (or edit current) to ProductList before he can place it in invoice. So he opens a ProductForm where all the products are retreived (again).
It could also be in opposite order, that user first edits Products, and then without closing the Products Form, opens new Invoice. The principle is that data is two times loaded, and effectively its the same data.
What is the propper way to handle this scenario, so we can tell one form that data is already loaded, and to retrieve that data from memory? And when all the consumers (Forms) of the data are closed, then also the data should be released from memory? Or I am going in wrong direction, and there is a better way?
Thanks,
Goran
Definitelly go with data loaded "twice" or you will introduce much worse problems.
Sharing data means sharing ObjectContext. Even in WinForms application this is considered as bad approach. Check this article (it is about NHibernate but the description is valid for EF as well).
The problem is that ObjectContext is unit of work. If share context between two windows you can easily get into situation where you modify data in first window (without saving them!) and you continue in second window where you push save button but it will save data from both windows! You can't selectively save data only from one window when you share the context.
If the Controls that are using the data are all child controls of a shared Parent control, then you could just pass around the datacontext, so that they all shared the same datacontext.
However, the general use case with databases, which is what backs EF in most cases, is to read the data in each time that it is needed.
A solution to this if as you say you already have the item being used in one form is to just take a Refrence to that item into your new form.
So in the case Where you have an invoice which has a Product List and you want to add to the product list, you could pass the product list from the invoice to the opening product list.
There are some issues with this:
If another user changes the datasource while one has opened it (a.k.a. Concurrency)
Handling save don't save scenarios where they may have made a change in one area that they don't actually want added to the data.
However, unless it is a true performance issues, I would just load the data every time. You can simplify this a lot by using the repository pattern, so you can just call a single method to get a list of products or an invoice, or whatever part of data you need.