What is the design pattern for multi-layer cascading drop downs using knockout and knockout.mapping? - ajax

So I realize that this question can be seen as somewhat vague, but it's actually quite specific.
I started to write this out, then realized that lack of specific verbiage makes it sound vague. So let me put it this way.
I've got an Order object, that has customer data on it. It also has, for the sake of this example, a single order for a car.
The Car has a Category, Product, Year, Color. For the sake of this example, my Order page has 4 drop downs, which cascade one to another. Category populates Product populates Year populates Color.
(I was going to go with Make and Model, then realized using "Model" was getting confusing, haha.)
I've got several problems:
I've got multiple layers of dropdowns. Four, not just one.
My drop down objects are not related to each other specifically - that is to say, I use an id from Cateogry to populate Products, but Category does not come with Products when it's retrieved. This is different than the Cart example that KO has on their website.
I am stuck with the above architecture. I need to change a drop down, then send a service call to get the next drop down based on the selected drop downs id. I can't alter the service layer to nest the objects together.
My Order comes with child objects to indicate Make, Model, Year, Color. However, since these are different, I've been using the knockout.mapping keyed array and a custom binding handler to look up data object. Thankfully I only have to do this once, as after the object in the top level is replaced, it's fine.
I've been trying to use knockout.mapping to map the relevant objects, especially considering the key thing.
However, I'm totally open to just making the objects in knockout.
The problem I'm having, and this thing has really turned into a disaster, is that since everything is asynchronous, it's very difficult to resolve things in the proper order, aside from nesting within nesting within nesting.
Hence my question - I'm getting to the point where it seems like ditching knockout completely is the answer here, which doesn't seem right. It feels like I'm very close but it still doesn't work properly. (Often things load in the wrong order.) Unfortunately I can't really post the code because it's huge.
The thing is, it seems like it shouldn't be this hard. It feels like I'm missing a fundamental design pattern for knockout and drop down combos. Looking at the cart example, I'm starting to suspect that multi-layer cascading drop downs are just not feasible in knockout at the moment unless the data is all loaded ahead of time.
Am I actually missing the design pattern? If so, please elucidate. If not, go ahead and say so. I guess whichever more people agree with will be accepted.
Update
I realized after the first comment I got that I did not discuss much about some of the solutions I've tried.
So, basically yes, I've tried subscribing to the change event. I should emphasize that at the beating heart of this problem lies the fact that all of our calls to load these dropdowns are network calls.
The problem that happens is that the change event fires multiple times - once when you load the drop down, and again when the value is bound to the drop down. At least, that's been my experience.
What ends up happening is that any subscription will then fire multiple times. When it does, it causes the load to happen multiple times. Aside from the fact that I don't want to fire multiple times, there are often issues where the drop downs will get loaded incorrectly. My guess is that one of the times arrived "out of order" than the others.
I've gotten similar results with my various efforts. It really does seem to be pushing me toward some hackish stuff, like nesting 5 or 6 or 7 network calls inside of each other's callbacks. And it seems like there must be a better way.
I've tried computed observables to similar effect. I've tried loading things once via the MVC viewbag, etc. Every time I try something, I'm stymied by either something loading weird, the knockout.mapping plugin behaving strangely (it apparently will not add its key/mapping functions to existing knockout observables) or just ... some other weird issue.
Again, I ask, is this something knockout is simply incapable of? Is our situation just too peculiar? Or am I missing some method or function or object that would make all of this work?

Knockout subcribe event will solve your problem.. Its not too complicate I think..
If you think its complicate add a fiddle or code block.

Related

Vue approach to populating components

I can't seem to find any information how it would be best to put data inside a component. To define the problem, lets say we have a user table in a database and this table has an ID and maybe 30 fields with details about the user.
Now if I want to create a Vue component that shows a list of many users details, lets just call it <user-details>. To show this on a page, would you:
1) Call the database to get all users you want to show and get their ID, then do a for loop with <user-details id="xxx"> and make Vue do ajax call to some API and get the details?
2) OR, use the inline version <user-details id="xxx" name="user name" ...> with 30+ fields?
3) OR, have some specific Vue component for this user list, maybe it's users who did not validate email or something, then <users-not-validated> and use ajax?
The problem I see is, that in case 1, you already called the database for the IDs, then call the database once again with ajax with pretty much the same SQL.
In case 2, it's just annoying to fill so many fields out each time you use the component.
In case 3, you will end up with a TON of components...
How do you approach this?
You won't find such information because it's not Vue related. Vue doesn't care what you use it for and how you structure your data. It aims to allow you to do anything you want.
Just as it doesn't care what your folder structure looks like (because, at its core, all it needs in order to render is a single DOM element), it also doesn't care how you organize your API, how you structure your application, your pages or even your components.
Obviously, having this amount of freedom is not always a good thing. If you look around, you'll notice people who use Vue professionally have embraced certain patterns/structures which allow for better code reuse and more flexibility. Nuxt is one such good example.
To anyone just starting with Vue, I recommend trying to use Nuxt as soon as possible, even if its overkill for their little project because they will likely pick up some good patterns.
Getting down to your specific question, in terms of data API architecture, you always have to ask yourself: what's the underlying principle?
The underlying principle is to make your application as fast as possible. In order to do that, ideally, you want to fetch exactly how much data you want to display, but not more. Therefore:
when getting the same data, if you have a choice, always try to lower the number of requests. You don't want each item in the list to initiate a call to the server when it is rendered. Make a single call for the entire list (only fetching what you display in the list view) and call for details if the user requests it (presses the details button).
adjust your pagination to cater how many items you can display on a screen, but also according to how long it takes to load a page. If it takes too long, lower the pageSize and allow your items more padding. If you think about it, most people prefer a snappy app with fewer items on page (and generously padded items) to one which takes seconds to load each page and displays items so crummed they're hard to click/tap on or hard to follow in the list without losing the row.
However, you have to take these guidelines with a grain of salt. In the vast majority of cases fetching full data in one call makes little to no difference in user experience. Many times the delays have to do with server cold-starts (first call to a server takes longer, as it needs to "wake it up" - but all subsequent calls of the same type are faster), with unoptimized images or with bad internet connectivity (as in, it works poorly regardless of whether you receive only the names or the full list of details).
Another aspect to keep in mind is that getting all the data at once is a trade-off. You do get a slower initial call but afterwards you are able to do seamless animations between list view and detail view as the data is already fetched, no more loading required. If you handle the loading state graciously, it's a viable option in many scenarios.
Last, but not least, your 2nd point's drawback does not exist. You can always bind all the details in one go:
<user-details v-bind="user" />
is equivalent to
<user-details :id="user.id" :name="user.name" :age="user.age" ... />
To give you a very basic example, the typical markup for your use-case would be:
<div v-if="isLoadingUsers" />
<user-list v-else :users="users">
<user-list-item v-for="(user, key) in users"
:key="key"
v-bind="user"
#click="selectedUser = user" />
</user-list>
<user-details-modal v-bind="selectedUser" />
It's obviously a simplification, you might opt to not have a user details modal but a cool transform on the list item, making it grow and display more details, etc...
When in doubt, simplify. For example, only showing details for one selected item (and closing it when selecting another) will solve a lot of UI problems right off the bat.
As for the last question: whether or not to have different components for different states, the answer should come from answering a different question: how large should you allow your component to get? The upper limit is generally considered around 300 lines, although I know developers who don't go above 200 and others who don't have a problem having 500+ lines in a component).
When it becomes too large, you should extract a part of it (let's say the user-not-validated functionality into a sub-component) and end up with this inside the <user-detail> component:
<user-detail>
... common details (title, description, etc...)
<div v-if="user.isValidated">
...normal case
</div>
<user-not-validated v-bind="user" v-else />
... common functionality (action bar, etc...)
</user-detail>
But, these are sub-components of your <user-detail> component, which are extracted to help you keep the code organized. They shouldn't replace <user-detail> in its entirety. Similarly, you could extract the user-detail header or footer components, whatever makes sense. Your goal should be to keep your code neat and organized. Follow whatever principles make more sense to you.
Finally, if I had to single out one helpful guideline when taking code architecture decisions, it would definitely be the DRY principle. If you end up not having to write the same code in multiple places in the same application, you're doing it right.
Hope you'll find some of the above useful.

How do I preload items in a SproutCore ListView?

I've got a relatively fast SproutCore app that I'm trying to make just a tad bit faster.
Right now, when the user scrolls my SC.ListView and they scroll into view some list items that have not been loaded from the server (say from a relationship), the app automatically makes a call to the server to load these records. Even though this is fast, there is still a short period of time where my list items are blank.
I know that I can make them say "Loading..." or something like that (and I have), but I was wondering: is there was a way to pre-load my "off-screen" records so that as the user scrolls, the list items are already loaded?
My ListItemViews will be fairly large (pixel-wise), so even loading double the amount of data is not going to be killer from an AJAX perspective, and it would be nice if as the user scrolled, the content was always loaded (unless they scroll SUPER-SUPER-fast, in which case I'm okay with them seeing a loading indicator).
I currently found a solution by adding the following to my SC.ListView, but I've noticed some major performance issues on mobile and they are directly related to making this change, so I was wondering if there was a better way.
contentIndexesInRect: function(rect) {
rect.height = rect.height * 2;
return sc_super();
}
Overriding contentIndexesInRect is the way I would do this. I would do less than double it though – I might get the result from sc_super() and then add a few extra items to the resulting index set. (I believe it comes back frozen, so you may have to clone-edit-freeze.) One or two extra may give you enough breathing room to get the stuff loaded, without contributing nearly as much to the apparent performance issue.
I'm surprised that it results in major performance issues though. It sounds to me like your list items themselves may be heavier-weight than they need to be – for example, they may have a lot of bindings to hook and unhook. If that's what's going on, you may benefit more from improving their efficiency.
I think you would be better served to load the additional data outside of the context of what the list is actually displaying. For instance, forcing more list items to render in order to trigger additional requests does result in having the extra data available, but also adds several unnecessary elements to the DOM, which is actually detrimental to overall performance. In fact these extra elements are most likely the cause of the major slowdown on mobile once you get to a sufficient number of extras.
Instead, I would first ensure that your list item views are properly pooling so that only the visible items are updating in place with as little DOM manipulation as possible. Then second, I would lazily load in additional data only after the required data is requested. There are quite a few ways to do this depending on your setup. You might want to add some logic to a data source to trigger an additional request on each filled request range or you might want to do something like override itemViewForContentIndex in SC.CollectionView as the point to trigger the extra data. In either case, I imagine it could look something like this,
// …
prefetchTriggered: function (lastIndex) {
// A query that will fetch more data (this depends totally on your setup).
var query = SC.Query.remote(MyApp.Record, {
// Parameters to pass to the data source so it knows what to request.
lastIndex: lastIndex
});
// Run the query.
MyApp.store.find(query);
},
// …
As I mention in the comments above, the structure of the request depends totally on your setup and your API so you'll have to modify it to meet your needs. It will work better if you are able to request a suitable range of items, rather than one-at-a-time.

What is the biggest performance issue in Emberjs?

Last 6 months I'm developing an Emberjs components.
I started had first performance problems when I tried develop a table component. Each cell in this table was Ember.View and each cell had a binding to object property. When the table had 6 columns and I tried to list about 100 items, it caused that browser was frozen for a while. So I discovered, that it is better write a function which return a string instead of using handlebars and handle bindings manually by observers.
So, is there any good practice how to use minimum of bindings? Or how to write bindings and not lose a lot of performance. For example... not use bindning for a big amount of data?
How many Ember.View objects is possible append to page?
Thanks for response
We've got an ember application that displays 100s of complex items on a single page. Each item uses out-of-box handlebars bindings to output about a dozen properties. It renders very quickly (< 100ms) and very little of that time is spent on bindings.
If you find the browser is hanging at 6 columns and 100 items there is for sure something else is wrong.
So, is there any good practice how to use minimum of bindings? Or how to write bindings and not lose a lot of performance.
Try setting Ember.LOG_BINDINGS = true to see what is going on. Could be the properties you are binding to have circular dependencies or costly to resolve. See this post for great tips on debugging:
http://www.akshay.cc/blog/2013-02-22-debugging-ember-js-and-ember-data.html
How many Ember.View objects is possible append to page?
I don't believe there is a concrete limit, for sure it will depend on browser. I wouldn't consider optimizing unless there were more than a few thousand.
Check out this example to see how ember can be optimized to handle very large tables:
http://addepar.github.com/ember-table/
Erik Bryn recently gave a talk about Ember.ListView which would drastically cut down the number of views on a page by reusing list cells which have gone out of the viewport.
Couple this technique with group-helper to reduce the number of metamorph script tags if your models multiple properties at the same time. Additionally, consider using {{unbound}} if you don't need any of the properties to live update.

Stories and Scenarios that implies UI

I am trying to learn how to use BDD for our development process and I sometimes end-up writing things that implies a UI design, so for brand new development or new features, the UI does not always exists.
For example, if I say this in a scenario "When a column header is clicked" it implies that this feature is based on some sort of table or grid, but at this point we are still just writing user-stories so there is no UI yet.
That gets me confused to know at what point in the process do we come up with a UI design ?
Keep in mind, I only have read articles about BDD and I think it would help our team a lot but still very new at this! Thx!
If you write your scenarios with a focus on the capabilities of the system, you'll be able to refactor the underlying steps within those scenarios more easily. It keeps them flexible. So I'd ask - what does clicking the column get for you? Are you selecting something? What are you going to do with the selection? Are you searching for something and sorting by a value?
I like to see scenarios which say things like:
When I look for the entry
When I go to the diary for January
When I look at the newest entries
When I look at the same T-shirt in black
These could all involve clicking on a column header, but the implementation detail doesn't matter. It's the capability of the system.
Beneath these high-level scenarios and steps I like to create a screen or page with the smaller steps like clicking buttons in it. This makes it easy to refactor.
I wrote this in a DSL rather than English, but it works with the same idea - you can't tell from the steps whether it's a GUI or a web page, and some of the steps involve multiple UI actions:
http://code.google.com/p/wipflash/source/browse/Example.PetShop.Scenarios/PetRegistrationAndPurchase.cs
Hope you find it interesting and maybe it helps. Good luck!
I guess you can write around that by saying "when I sort the information by X, then..." But then you would have to adjust your scenario to remove any mention of the data being displayed in a grid format, which could lead to some rather obtuse writing.
I think it's a good idea to start with UI design as soon as you possibly can. In the case you mentioned above, I think it would be perfectly valid to augment the user story with sketch of the relevant UI as you would imagine it, and then refine it as you go along. A pencil sketch on a piece of paper should be fine. Or you could use a tablet and SketchBook Pro if you want something all digital.
My point is that I don't see a real reason for the UI design to be left out of user stories. You probably already know that you're going to build a Windows, WPF, or Web application. And it's safe to assume that when you want to display tabular data, you'll be using a grid. Keeping these assumptions out of the requirements obfuscates them without adding any real value.
User stories benefit from the fact, that you describe concrete interactions and once you know concrete data and behaviour of the system for it, you might as well add more information about the way you interact. This allows you to use some tools like Cucumber, which with Selenium enables you to translate a story to a test. You might go even further and e.g. for web apps capture all pages you start concrete story at and collect all interactions with that page resulting in some sort of information architecture you might use for documentation or prototyping and later UI testing.
On the other hand, this makes your stories somewhat brittle when it comes to UI changes. I think the agile way of thinking about this is same as when it comes to design changes - do not design for the future, do the simplest possible thing, in the future you might need to change it anyway.
If you stripped your user stories of all concrete things (even inputs) you will end up with use cases(at least in their simplest format, depends on how you write your stories). Use cases are in this respect not brittle at all, they specify only goals. This makes them resistant to change, but its harder to transfer information automatically using tools.
As for the process, RUP/UP derives UI from use cases, but I think agile is in its nature incremental (I will not say iterative, this would exclude agile methods like FDD and Kanban). This means, as you implement new story, you add to your UI what is necessary. This only makes adding UI specifics in stories more reasonable. The problem is, that this is not a very good way to create UI or more generally UX(user experience). This is exactly what one might call a weakpoint of agile. The Agile manifesto concentrates on functional software, but that is it. There are as far as I know no agile techniques for designing UI or UX.
I think you just need to step back a bit.
BAD: When I click the column header, the rows get sorted by the column I clicked.
GOOD: Then I sort the rows by name, or sometimes by ZIP code if the name is very common, like "Smith".
A user story / workflow is a sequence of what the user wants to achieve, not a sequence of actions how he achieves that. You are collecting the What's so you can determine the best How's for all users and use cases.
Looking at a singular aspect of your post:
if I say this in a scenario "When a column header is clicked" it implies that this feature is based on some sort of table or grid, but at this point we are still just writing user-stories so there is no UI yet.
If this came from a user, not from you, it would show a hidden expectation that there actually is a table or grid with column headers. Even coming from you it's not entirely without value, as you might be a user, too. It might be short-sighted, thinking of a grid just because it comes from an SQL query, or it might be spot-on because it's the presentation you expect the data in. A creative UI isnÄt a bad thing as such, but ignoring user expectations is.

How much logic should you put in the UI class?

I'm not sure if this has been asked or not yet, but how much logic should you put in your UI classes?
When I started programming I used to put all my code behind events on the form which as everyone would know makes it an absolute pain in the butt to test and maintain. Overtime I have come to release how bad this practice is and have started breaking everything into classes.
Sometimes when refactoring I still have that feeling of "where should I put this stuff", but because most of the time the code I'm working on is in the UI layer, has no unit tests and will break in unimaginable places, I usually end up leaving it in the UI layer.
Are there any good rules about how much logic you put in your UI classes? What patterns should I be looking for so that I don't do this kind of thing in the future?
Just logic dealing with the UI.
Sometimes people try to put even that into the Business layer. For example, one might have in their BL:
if (totalAmount < 0)
color = "RED";
else
color = "BLACK";
And in the UI display totalAmount using color -- which is completely wrong. It should be:
if (totalAmount < 0)
isNegative = true;
else
isNegative = false;
And it should be completely up to the UI layer how totalAmount should be displayed when isNegative is true.
As little as possible...
The UI should only have logic related to presentation. My personal preference now is to have the UI/View
just raise events (with supporting data) to a PresenterClass stating that something has happened. Let the Presenter respond to the event.
have methods to render/display data to be presented
a minimal amount of client side validations to help the user get it right the first time... (preferably done in a declarative manner) screening off invalid inputs before it even reaches the presenter e.g. ensure that the text field value is within a-b range by setting the min and max properties.
http://martinfowler.com/eaaDev/uiArchs.html describes the evolution of UI design. An excerpt
When people talk about self-testing
code user-interfaces quickly raise
their head as a problem. Many people
find that testing GUIs to be somewhere
between tough and impossible. This is
largely because UIs are tightly
coupled into the overall UI
environment and difficult to tease
apart and test in pieces.
But there are occasions where this is
impossible, you miss important
interactions, there are threading
issues, and the tests are too slow to
run.
As a result there's been a steady
movement to design UIs in such a way
that minimizes the behavior in objects
that are awkward to test. Michael
Feathers crisply summed up this
approach in The Humble Dialog Box.
Gerard Meszaros generalized this
notion to idea of a Humble Object -
any object that is difficult to test
should have minimal behavior. That way
if we are unable to include it in our
test suites we minimize the chances of
an undetected failure.
The pattern you are looking for may be Model-view-controller, which basically separates the DB(model) from the GUI(view) and the logic(controller). Here's Jeff Atwood's take on this. I believe one should not be fanatical about any framework, language or pattern - While heavy numerical calculations probably should not sit in the GUI, it is fine to do some basic input validation and output formatting there.
I suggest UI shouldn't include any sort of business logic. Not even the validations. They all should be at business logic level. In this way you make your BLL independent of UI. You can easily convert you windows app to web app or web services and vice versa. You may use object frameworks like Csla to achieve this.
Input validations attached to control.
Like emails,age,date validators with text boxes
James is correct. As a rule of thumb, your business logic should not make any assumption regarding presentation.
What if you plan on displaying your results on various media? One of them could be a black and white printer. "RED" would not cut it.
When I create a model or even a controller, I try to convince myself that the user interface will be a bubble bath. Believe me, that dramatically reduces the amount of HTML in my code ;)
Always put the minimum amount of logic possible in whatever layer you are working.
By that I mean, if you are adding code to the UI layer, add the least amount of logic necessary for that layer to perform it's UI (only) operations.
Not only does doing that result in a good separation of layers...it also saves you from code bloat.
I have already written a 'compatible' answer to this question here. The rule is (according to me) that there should not be any logic in the UI except the UI logic and calls for standard procedures that will manage generic/specific cases.
In our situation, we came to a point where form's code is automatically generated out of the list of controls available on a form. Depending on the kind of control (bound text, bound boolean, bound number, bound combobox, unbound label, ...), we automatically generate a set of event procedures (such as beforeUpdate and afterUpdate for text controls, onClick for labels, etc) that launch generic code located out of the form.
This code can then either do generic things (test if the field value can be updated in the beforeUpdate event, order the recordset ascending/descending in the onClick event, etc) or specific treatments based on the form's and/or the control's name (making for example some work in a afterUpdate event, such as calculating the value of a totalAmount control out of the unitPrice and quantity values).
Our system is now fully automated, and form's production relies on two tables: Tbl_Form for a list of forms available in the app, and Tbl_Control for a list of controls available in our forms
Following the referenced answer and other posts in SO, some users have asked me to develop on my ideas. As the subject is quite complex, I finally decided to open a blog to talk about this UI logic. I have already started talking about UI interface, but it might take a few days (.. weeks!) until I can specifically reach the subject you're interested in.

Resources