conceptacid
conceptacid

Reputation: 348

How to prevent content from scrolling when Meteor updates the collection

My question is very similar to this one and that one but not exactly the same.

I have the following template in my Meteor application:

<template name="items">
    <div class="mainframe">
    <h3>Available items:</h3>
        <div class="items-table-container">
            <table class="table table-hover">
                <tbody>
                    {{#each all_items}}
                       {{> item}}
                    {{/each}}
                </tbody>
            </table>
        </div>
    </div>
    <div class="btn-group">
    <button id="create" class="btn">Create new item</button>
    </div>
</template>

The template function is trivial:

Template.items.all_items = function () {
    return Items.find({}, {sort: {name: 1}}).fetch();
}

There is also an event bound to the #create button which inserts a new item into the Items collection and that works fine.

Now the most important part is the CSS:

.items-table-container {
    height:340px;
    overflow-y: scroll;
}

So basically I want my table to have scrollable content inside a fixed size area. The problem start when I scroll down the contents of the items table in one browser and then in another browser I add a new item. The first browser updates the list of items and scrolls the contents back to the top position.

The question is how can I prevent auto update for a single template? I think in this particular case I actually need something like the traditional web page update: that's Ok if a user doesn't see a newly added item immediately but rather after he reloads the page.

Another idea is to do some kind of pagination instead of the scrollable content. I think that would solve the problem however this would be much more complicated and I would like to avoid that.

I think ideally I would like to be able to tell Meteor that I want Meteor to update the template not when the model changes but rather by a request.

Upvotes: 3

Views: 2457

Answers (4)

Kevin
Kevin

Reputation: 4297

You could also have jquery handle fixing the scroll position. My use-case was having something inserted above the current scroll point in the main body document scrolled text lower.

Not sure yet how to get meteor to run a callback every time a publish set is updated, but you should get the idea:

before = document.body.scrollHeight
// insert your elements
after = document.body.scrollHeight

if $(document).scrollTop() != 0
  # scroll us equal to the amount of scroll height added
  window.scrollTo(0, $(document).scrollTop()+(after-before) )

Upvotes: -1

Doug
Doug

Reputation: 832

Isolate the array iteration.

{{#isolate}}
  {{#each all_items}}
    {{> item}}
  {{/each}}
{{/isolate}}

Upvotes: 3

Tarang
Tarang

Reputation: 75955

Put your list of items in another template inside the scrollable div container:

<template name="items">
    <div class="mainframe">
    <h3>Available items:</h3>
        <div class="items-table-container">
            <table class="table table-hover">
                <tbody>
                    {{> myitems}}
                </tbody>
            </table>
        </div>
    </div>
    <div class="btn-group">
        <button id="create" class="btn">Create new item</button>
    </div>
</template>

<template name="myitems">
    {{#each all_items}}
        {{> item}}
    {{/each}}
</template>

Javascript:

Template.myitems.all_items = function () {
    return Items.find({}, {sort: {name: 1}}).fetch();
}

//Template.items.all_items = function () {
// remove this helper
//}

This way you can keep the reactivity without putting in a request to update it. Only the portion inside the scrollable box is re-rendered, keeping the position the scrollable container was scrolled to.

Edit: To preserve/freeze your content you could use the preserve function, it takes a css selector as input. e.g

Template.items.preserve(['.items-table-container']);

Upvotes: 4

nagle
nagle

Reputation: 39

To make a whole region constant so that it doesn't rerender, you can use the block helper {{#constant}}.

If you have specific DOM elements to preserve you can use Template.myTemplate.preserve() which takes as arguments the selectors of the nodes to preserve.

Upvotes: 1

Related Questions