stop meteor rerender every child template inside of each block when find query changes? - templates

i'm rendering a list of elements based on a collection on the meteor server.
the elements are rendered using an #each block which is populated from a helper method that returns a cursor which is the result of a find query. in order to sort the list based on some attribute of its data i run a new find with a different sort option.
this works fine and the list is rendered in the desired order. the problem is meteor is rerendering each element.
now i have two problems:
1) the elements can contain an embedded video that is playing. this is reset when meteor rerenders the element
2) i want to have some css transitions animate the repositioning of the elements. since meteor rerenders every element in the dom, the css transitions don't work.
i was partially able to solve problem #1 using a constant block but problem #2 remains a mystery. i could do all the sorting and filtering client side without relying on meteor but that seems clumsy.
is there any way that meteor can just reposition the elements in the dom instead of removing and readding them?
in the documentation for renderList i found this (which makes it seem like meteor could at least theoretically do what i want):
renderList is more efficient than using Meteor.render to render HTML for a list of documents. For example, if a new document is created in the database that matches the query, a new item will be rendered and inserted at the appropriate place in the DOM without re-rendering the other elements. Similarly, if a document changes position in a sorted query, the DOM nodes will simply be moved and not re-rendered.

Related

Apollo useQuery stuck in loading = true condition after offline mutation

16m
I am trying to complete a robust offline React, PWA using Apollo.
I have a functional component that uses useQuery to retrieve a list of items. It is using the default fetchPolicy. When this component renders, it successfully retrieves the data. If I am online or offline it works just fine.
If I am offline and I make a call to useMutation to create a new item, the list updates correctly, since I am using optimisticResponse and the update feature of mutations.
The problem happens when I navigate away from the list component, so that it is no longer rendered, then I return. Upon returning, the functional component that list all of the items is rendered again, it is stuck in the loading=true condition since I invoked the mutation. All this time the app is still offline. While in this loading state, I try to create another item while offline. The list never optimistically updates in this situation.
What do I have to do to get this to work? Is there a fundamental flaw to my basic approach to making this an offline-first app?
Here is a summary of the steps that create the problem.
Functional component executes a query and retrieves a list of items and renders them without issues.
Place the app offline.
While the list component is still rendered, invoke a mutation to create a new item while offline.
Optimistically update the UI (by updating the cache) with no issues.
Navigate away from the list component.
Navigate back to the list component (forcing a rerender of the entire list component)
The list component useQuery/loading value is stuck in true condition.
Attempt to create another item the same way as before.
The list does not optimistically update.
I cannot seem to figure this one out.

MathJax + Ember.js Re-rendering issue

I've encountered an issue with ember's (app is on 2.6.0, but seems to happen in latest as well) rendering process and its compatibility with the MathJax.js library. I have an ember twiddle (linked below) that isolates the problem, but essentially it seems like MathJax's rendering of inline equations that occur in the middle of a single text node breaks ember's re-rendering, in that the single text node becomes multiple text nodes after MathJax transforms the inline equation text into its Math elements, and the 2nd text node becomes orphaned, and remains in the DOM across re-renders.
https://ember-twiddle.com/cadfb80d7c90df98353cc3d9900f2b73/1ab7f66c3c6ca4aad15bf443bbe02fbb1f79a0d4?openFiles=controllers.application.js%2C
It may just be that my integration of mathjax with ember is just not correct, so I'd love some pointers if thats the case.
I was able to fix this with a somewhat hacky workaround:
https://ember-twiddle.com/cadfb80d7c90df98353cc3d9900f2b73
The issue (as confirmed on slack by some ember core team members) is with how MathJax modifies the DOM, in that ember is not able to keep track of the extra nodes it creates, and as a result can not properly clean up after it on re-renders.
To solve this, the component which contains the mathjax content manually sets its element's innerHTML to whatever the content attribute is set to when didRender() is fired, effectively wiping out all the DOM created/modified by MathJax. MathJax's rendering process is then invoked to render any formulas in the newly rendered content.
Note that if your content does not contain any HTML, it is recommended to set element.innerText instead of element.innerHTML.

Ember Unit testing: counting new items rendering

I wrote a controller that holds a list, and by clicking a "get more" button, renders 5 more items of that list. I want to create some tests for that, and I want to validate that it only renders 5 more items (instead of re-rendering the entire list).
Is this even possible?
It very depends on what 're-rendering' is for you.
You can check if IDs of the old items were not changed and if their state is still valid. This was an issue that I have to solve by using Ember.ArrayProxy.
If you want to test if browser have to re-render it, you can try to count number of execution of 'init' method - https://guides.emberjs.com/v2.6.0/components/the-component-lifecycle/

Display a webpage while rendering

I'm putting together a website, where one of the pages holds an interactive map. The map is implemented as a big table, where each node is a td.
Now this map takes a while to render, and so, I'd love for the site to be displayed as it renders, so that even if the map is not fully rendered, the user can click links or the part of the map that is rendered.
Is there an easy way to do this? AJAX is one option, but since it is a Django website and the map depends on data from the Django template, AJAX becomes a bit unwieldy.
So is there a way to make the page visible while rendering?
(I considered making each node an iframe, so that they would be rendered individually, but that seems a bit silly too)
the django template should only render an empty map (or a map holding the first 10 points) with the javascript code firing on page ready
this javascript script should do this:
request 10 nodes from django (using a different url/view)
render the fetched nodes into the page
if no more nodes: END
goto 1.
Hope this helps
After trying a few different things, it seems that the problem was too many database queries. Each of the nodes made calls to the database while rendering, which caused them to be very slow.
For reference:
Custom filters in Django should not make database queries, if they are used heavily on a page

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.