I'm currently experiencing very unusual behavior when using the each method of a Backbone collection. In my app, I allow users to edit existing models, which includes editing and adding a number of time constraints to that model. The model and its time constraints are linked with Backbone Relational. Every time the user clicks to add a new time constraint, I add a TimeConstraint model to the relationship without saving it. If a user then decides to cancel the edit, all new/unsaved TimeConstraints should be removed from the relationship. However, when I'm looping over my collection, it doesn't seem to perform the final iteration.
I constructed a jsfiddle to demonstrate this behavior here: http://jsfiddle.net/richardstokes/ZzFgZ/9/
The steps to follow are:
Click "Edit Policy"
Add 2 or more new time constraints using the "New Time Constraint" button
Cancel the edits by clicking "Cancel Edits"
You'll notice the console prints the starting length of the time_constraints collection and the finishing length, as well as intermediate lengths after removing unsaved models. It always seems to stop short and leave one item in the collection, even though they're all new/unsaved.
I would greatly appreciate if someone would help me with this problem, it's had me stuck literally all day.
You're removing items as the collection of timeConstraints is being iterated, which might be causing undefined behavior. Try first getting the list of new timeConstraints, then passing them as an array to remove():
var toRemove = this.model.get('time_constraints').filter(function (timeConstraint) {
return timeConstraint.isNew();
});
this.model.get('time_constraints').remove(toRemove);
Related
How can I invalidate a single item when working with useInfiniteQuery?
Here is an example that demonstrates what I am trying to accomplish.
Let`s say I have a list of members and each member has a follow button. When I press on to follow button, there is a separate call to the server to mark that the given user is following another user. After this, I have to invalidate the entire infinite query to reflect the state of following for a single member. That means I might have a lot of users loaded in infinite query and I need to re-fetch all the items that were already loaded just to reflect the change for one item.
I know I can change the value in queryClient.setQueryData when follow fetch returns success but without following this with invalidation and fetch of a member, I am basically going out of sync with the server and relying on local data.
Any possible ways to address this issue?
Here is a reference UI photo just in case if it will be helpful.
I think it is not currently possible because react-query has no normalized caching and no underlying schema. So one entry in a list (doesn't matter if it's infinite or not) does not correspond to a detail query in any way.
If you prefix the query-keys with the same string, you can utilize the partial query key matching to invalidate in one go:
['users', 'all']
['users', 1]
['users', 2]
queryClient.invalidateQueries(['users]) will invalidate all three queries.
But yes, it will refetch the whole list, and if you don't want to manually set with setQueryData, I don't see any other way currently.
If you return the whole detail data for one user from your mutation, I don't see why setting it with setQueryData would get you out-of-sync with the backend though. We are doing this a lot :)
Here's my fiddle attempt combining code on the Knockout cascading Cart Editor live example on the Knockoutjs.com site, and with RP Niemeyer's example of data binding nested arrays to try and achieve a cascading cart extended with product options in the functional format given by Niemeyer.
Why doesn't the quantity field update the subtotal?
Why doesn't 'Remove' work?
Why does formatCurrency(price) produce a 'unable to parse bindings' error?
Why does it happen that changing the product field doesn't update the price but if 'Add Product' button is pressed the change will appear in the next line?
In Niemeyer's example 'add-product' and is a methods inside the scope of the functions rather than the cartLine, which I copied for the 'subtotal' method - which is the better place to handle these operations?
Thanks to the work of S.Sanderson, R.P.Niemeyer, J.Papa for their incredible effort in the community to promote Knockout. It's awesome!
Alright, so your fiddle is a bit more complicated than it needs to be, but I have tried to leave the structure alone in case you were planning to expand. I do have a few questions though, but I'll get to those at the end. First, your questions:
You had several quantity and subtotal properties, one on each object (line, category, and product). Your layering had confused them (and me, honestly). I removed the extra quantity and subtotal properties on your models, the didn't really make sense anyway, but I left them in your data. Your should really sort out what you want this to look like.
Your layering was wrong, the removeLine was looking for a function on the cartLine, and sending the product, but you had the function on the viewmodel and needed the cartLine. Moving the remove line to the outermost context fixed this.
I didn't get this error.
Your price was not getting update properly. This was a context-layering issue.
I think you linked to the wrong fiddle for Niemeyer, the one you linked has no product in it.
Here is a working fiddle for your code. It's still a bit messy because, again, I tried not to mess with more than I needed to. You really should consider restructuring the data and/or viewmodels though, it doesn't need to be this complex. I removed some of the layering though, since it didn't match your viewmodel.
Also, your category.subscribe method was INSIDE the computed observable for subtotal. I moved it outside, onto the model.
NOTE: I am using knockout2.0 in the fiddle. Please consider updating. Knockout1.3Beta does not implement control flow in the same way, and this was causing a seperate error I didn't talk about.
So, my questions:
Why is there a quantity on both product and options in the data and object defintions?
Why is there a subtotal on each of product, category and cartLine?
Why is there a grandtotal on menu and viewmodel?
3a. Why is there a grandtotal on menu at all? This makes no sense.
How are folks generally handling the whitelisting of foreign key values? Let's ignore the use case of an associated user record which brings an additional set of issues and stick to a fairly benign scenario: A Task belongs to a Project. When I create the task, I want to create it with its project_id value, but I don't want that value to be editable. The property is passed by a hidden field in the shared form.
I know I could just unset that property in the controller before calling save() in the edit action, but I was wondering whether anyone had a better solution. I've used/tried several, but all are laborious or less "universal" than I'd like.
Does anyone have a solution that they really like to solve this particular problem?
Thanks.
I handle this manually as well. The process is something like this.
Load object and show the edit screen to the user.
When user submits, take the primary ID and load the object again. Check ownership.
Have a whitelist of user editable fields, loop through those keys and populate your new object, leave everything else alone.
Save.
You could move this into some kind of before save hook or behavior I would say. But this seems the best practice with the RoR feature (we all know what happened in GitHub)
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.
I've got a situation which I want to fetch data from a database, and assign it to the tooltips of each row in a ListView control in WPF. (I'm using C# 4.0.) Since I've not done this sort of thing before, I've started a smaller, simpler app to get the ideas down before I attempt to use them in my main WPF app.
One of my concerns is the amount of data that could potentially come down. For that reason I thought I would use LINQ to SQL, which uses deferred execution. I thought that would help and not pull down the data until the user passes their mouse over the relevant row. To do this, I'm going to use a separate function to assign the values to the tooltip, from the database, passed upon the parameters I need to pass to the relevant stored procedures. I'm doing 2 queries using LINQ to SQL, using 2 different stored procedures, and assigning the results to 2 different DataGrids.
Even though I know that LINQ to SQL does use deferred execution, I'm beginning to wonder if some of the code I'm writing may defeat my whole intent of using LINQ to SQL. For example, in testing in my simpler app, I am choosing several different values to see how it works. One selection of values brought no data back, as there was no data for the given parameters. I thought this could potentially cause the user confusion, so I thought I would check the Count property of the list that I assign from running the DBML associated method (related to the stored procedure). Thinking about it, I would think it would be necessary for LINQ to run the query, in order to give me a result for the Count property. Am I not correct?
If I eliminate the call to the list's Count property, I'm still wondering if I might have a problem; if LINQ may still be invoked, because I'm associating the tooltip to the control via a function call?
You are correct, when you call the Count property it iterates over the result set. Not clear on your last question, but the LINQ probably gets called at the point where you populate your DataGrids, way after the tooltip comes into play.
EDIT: however, this does not mean there is anything wrong with deffered execution or your use of it, it executes at the latest possible stage, right when you need the data. If you still want to check the Count ahead of actually fetching all the data, you could have a simple LINQ to SQL function that checks for Any() rows. (Actually Any() is probably what you want more than Count > 0)
You should use Any(), not Count(), but even Any() will cause the query to be executed - after all, it can't determine whether or not there are any rows in the result set without executing the query. But there's executing the query, and there's fetching the result set. Any() will fetch one row, Count() will fetch them all.
That said, I think that having a non-instantaneous operation that occurs on mouseover is just a bad idea. There was a build of Outlook, once, that displayed a helpful tooltip when you moused over the Print button. Less helpfully, it got the data for that tooltip by calling the system function that finds out what printers are available. So you'd be reaching for a menu, and the button would grab the mouse pointer and the UI would freeze for two seconds while it went out and figured out how to display a tooltip that you weren't even asking for. I still hate this program today. Don't be this guy.
A better approach would be to get your tooltip data asynchronously after populating the visible data on the screen. It's easy enough to create a BackgroundWorker that fetches the data into a DataTable, and then make the DataTable available to the view models in the RunWorkerCompleted event handler. (Do it there so that you don't do any updates to UI-bound data on the UI thread.) You can implement a ToolTip property in your view model that returns a default value (probably null, but maybe something like "Fetching data...") if the DataTable containing tool tip data is null, and that calculates the value if it's not. That should work admirably. You can even implement property-change notification so that the ToolTip will still get updated if the user keeps the mouse pointer over it while you're fetching the data.
Alex is correct that calling Count() or Any() will enumerate the LINQ expression causing the query to execute. I would recommend re-thinking your design as you probably don't want a query to the database executed every time the user moves his/her mouse. There is also the issue of the delay to query the database. What might be instantaneous on your dev box with a local database might have a multi-second delay on a heavily loaded server. I would recommend creating a DisplayTooltip() function that takes a lazily evaluated LINQ expression. You can then cache the results or apply other heuristics to decide whether you should actually be querying the database or not.