How do I tell Meteor to stop publishing changes on a collection (for a moment)?
Also how to tell it to resume and that the collection changed?
Basically (on the server):
People = new Meteor.Collection("people")
insertPeople = ->
// Don't notify clients of the following changes
// Insert a bunch of people into the People collection
// Resume notifications
Put a flag in each document, 'updating'.
Add the new ones with this set to true; render their template with a css class that hides them based on this field.
When ready, update the collection to updating: false. They will be visible pretty quickly.
This being said, there are events you can plug into to make transitions more pleasant/animated. Didn't think you were asking that, but it may be a better answer.
To the comment:
Inserting a template for an additional document triggers DOM changes, which are fairly expensive, and then the device has to figure out how to display. Updating a property requires just the second part, that the device has to figure out how to display.
Related
I've been working with Quill for a short time and have been focused on getting collaborative editing working. So far it's going well and I have a fully working collaborative editor!
I want to show the selection and cursor position of other users, but I can't think how to properly approach this problem with Quill.
I essentially want to add markup to the rendered document, without adding any content to the actual document model. Is this possible? Where should I start?
You need to use "quill-cursors" package and then listen to selection-change event:
editor.on("selection-change", function (range, oldRange, source) {
console.log("Local cursor change: ", range);
});
Then broadcast this data to other remote users, and then render the remote cursor:
const cursors = editor.getModule("cursors");
cursors.createCursor(id, user.name, userColor);
cursors.moveCursor(id, cursorRange); // <== cursor data from previous step
cursors.toggleFlag(id, true);
In Quill 0.20, there was an example with multiple cursors working. The approach was a sibling absolutely positioned <div> that contained the cursors and synchronized with selection-change information from the editor. To not delay the 1.0 release this demo and feature was not updated with the new API but support is planned. You can try a similar approach in the meantime and of course the code is still available. You can also track the feature on Github Issues.
Trying to do an infinite scroll page that displays elements as the user scrolls.
So each time I detect that the scroll reaches the end of the page I call
this.recordLimit += 10;
this.subscribe('movements', {limit: this.recordLimit});
and that triggeres (autorun)
this.autorun(h => {
if (this.ready()) {
this.items = Items.find(<potential limit filter here too>);
}
All right. That is working. However each time this.items = Items.find(); is called, the user's browser is scrolled back up to the top.
Potentially this is because the dom elements are removed, the scroll is reset, and then the elements are added again without restoring the previous scroll position.
What am I doing wrong ?
Examples where it is 'apparenty' working:
https://github.com/barbatus/ng-infinite-scroll/blob/master/scroll-controller.js
https://github.com/abecks/meteor-infinite-scroll
http://meteorpedia.com/read/Infinite_Scrolling
############ Edit #############
Actually, I noticed that, putting after the Items.find() a h.stop() to stop the subscription, this works... I guess the previous mango cursor is updated with the last subscription limit.
However I am still not able to understand why this was repainting everything in the initial case..
I believe the problem is you're finding the documents again as you guessed. You should only subscribe to your publication in the autorun. Check this from Angular2 & Meteor tutorial which explains pub/sub pretty well.
In the autorun, it will rerun the find() and re-render all the documents which is why you need to rerun only the subscription in autorun for your case. Because of how pub/sub and observers work, since the only thing you change is the "limit" in your function and the rest is the same, your publish will only return the new documents, and keep the previously returned ones. The find() query on the client side will fetch the documents returned from the pub/sub and it won't rerender the already fetched documents when the amount of documents change.
I'm using an older version of fullCalendar (1.6.4) with mostly success. I've got a UI that has the ability to add new events to the calendar, and then edit them inline. I'm running into problems when I try to then update the calendar with the modified event object. I'm only running into this problem however with dynamically added events, I can apparently reload the page and update events that fullCalendar adds initially just fine.
The problem seems very related to how the event.source property works. When the property is null on the event, fullCalendar pushes a new instance of the event onto the "cache" object, even if the event otherwise exists on the calendar already. I'm not sure why or how this works. For whatever reason though, I then end up with duplicate instances of the event on the calendar day.
// code directly from fullCalendar 1.6.4
function renderEvent(event, stick) {
console.log('renderEvent',event)
normalizeEvent(event);
if (!event.source) {
if (stick) {
stickySource.events.push(event);
event.source = stickySource;
}
cache.push(event);
}
reportEvents(cache);
}
So, in cases that are a pure edit of an existing calendar item, I make sure the source value is set and not lost/nulled anywhere. Even if worst case it does the below and sets it to an empty object. (Note, this may be a cause of my problems, I just don't know enough about full calendar). Sometimes I even have to force it to be {}, otherwise it has multiple items in source and I again end up with duplicate calendar entries after updating.
calEvent.source = calEvent.source ? calEvent.source : {};
I then update my existing calendar with a call to renderEvent.
$('#calendar').fullCalendar( 'renderEvent', calEvent, true);
Unfortunately, I'm running into the case where the new calEvent sent to renderEvent is updated, and it does not update the instance on the calendar. This may be because of the source field? And it only happens for newly dynamically added events.
Can someone assist about how to properly edit events? And how this source field should properly be used.
On my site, users can recieve notifications on different events (such as a new comments on a user's post). Users can view these notifications on a special page in their profile. I want when a user come to that page that he can distinguish new ("unread") notifications. Namely, I want the following behavior:
When a user comes to a notifications page, any notification that has never before been shown on that page, is highlighted.
If a user leaves that page and comes later, only the new notifications (that has appeared in the meantime) are highlighted.
Each notification is highlighted for as long as the user stays on the page.
If a new notification appears while the user is on page, it is immediately loaded and shown and highlighted.
If a notification changes and/or is removed while the user stays on the page, the page reflects this change (preferably keeping the highlight status).
I start with having a Notifications collection that has a read field showing whether this notification is "read" (i.e. has already been shown). Now I can highlight only notifications that has read set to false. However, it will not get the required behavior in a simple way.
The main problem is point 3, because I must somehow mark that the notification has been read, but have this mark be taken into account only on the next visit to page.
For example, I might try to set notification's read field to true on template render (for example, in Template.notification.rendered), but it will immediately force notification template update and the highlighting will be removed.
So the particular problem is how to keep the initial value of read property and not redraw the template on this property change?
(I thought also of different approach such as relying on some user-side event such as user leaving the page, and updating read only then, but this does not seem to be reliable.)
For now, I have implemented the following solution:
//// html
<template name='notification'>
<li class="list-group-item {{notificationClass}}">
...
</li>
</template>
//// coffee
Template.notification.helpers
notificationClass: ->
if (this.read && UI._templateInstance().wasRead)
undefined # no highlight
else
"list-group-item-info" # highlight
Template.notification.rendered = ->
this.wasRead = this.data.read
this.data.markAsRead() # ultimately updates the collection
that is, on rendered event I set the template property to remember whether this notification was read initially. This template property does not change as long as the template exists (and even if notification data changes, the template property is there). In template helper, instead of directly accessing the notification read property, I check template property.
This seems to work, but looks too complicated for me. So:
Are there any major disadvantages in this approach? For example, can template's rendered code be re-executed while a user stays on the page?
Is there some better approach for my problem?
In my project i have a route that display a list of content.
Content is retreived by a subription and depends on 3 Session var.
At the begining i get 12 items in content. I have a pager that allow to get more data by modifying one of the Session dependency.
But when i do it, the list of content if completly removed and then fully re-rendered.
I tried to have a look inside the app with debugger. It seems that it is in Tracker.flush() method (from Tracker.js meteor file) that it happens.
while (pendingComputations.length) {
var comp = pendingComputations.shift();
comp._recompute(); // HERE IT WILL REMOVE ALL ITEMS AND THEN ADD ALL FROM THE SUBSCRIPTION
}
In fact it should just add new items to the template, and not remove them all and then adding them all again with new ones.
I use Iron Router, my app is on 0.9.3.1 (upgrade from 0.8.x).
[edit] precision about what i mean by "re-render" :
the list of items is completely removed from the template
and then the list appear again with old items and new items
because i do step-by-step debugging i cn say that when list template is cleared, in console i still have access to items collection, and the count on that collection returns me a number greater than 0
[edit] about a reproduction project
I'm working on, and i hope i'll be able to understand the problem to explain it. It's available here http://displaybugreproductionwithironrouterprogess.meteor.com
And source code is here https://github.com/Rebolon/meteor-ironrouterprogress-bug
If you just do a
meteor remove mrt:iron-router-progress
then the app runs correctly and the template is not fully re-rendered (so there is no clipping at the screen).