kadirahq / blaze-layout

Layout Manager for Blaze (works well with Meteor FlowRouter)
MIT License
198 stars 61 forks source link

force re-render #21

Closed Streemo closed 8 years ago

Streemo commented 9 years ago

Hi,

Would anyone like to see a force re-render functionality? Similar to my request of non-idemptotent routing.

{force:true} option would make the FlowLayout re-render the template, if we want to re-start onCreated callbacks for some reason.

kylestew commented 9 years ago

I'm running into that exact issue. If a user switches from route A to route B, but both employ the same template, onCreate only fires the first time. I was setting up a data context there, but now I've got to figure out a different way to do this. A force flag would seem like a good option.

sikanhe commented 9 years ago

^just put w.e onCreated stuff in a Tracker.autorun/this.autorun block, since FlowRouter.getParam is reactive

Streemo commented 9 years ago

that is the correct solution On Jun 10, 2015 3:25 AM, "sikanhe" notifications@github.com wrote:

^just put w.e onCreated stuff in a Tracker.autorun/this.autorun block, since FlowRouter.getParam is reactive

— Reply to this email directly or view it on GitHub https://github.com/meteorhacks/flow-layout/issues/21#issuecomment-110630207 .

kylestew commented 9 years ago

Hi @Streemo, I'm finding quite a few cases where this functionality would be needed.

_uihooks do not fire when transitioning between two instances of the same view. I believe this coincides with the issue where rendered is not called when transitioning between two instances of the same template.

Am I understanding correctly that Flow Router is re-using the existing template if its called a second time?

Sivli-Embir commented 9 years ago

:+1:

proehlen commented 9 years ago

+1

keviniamburg commented 9 years ago

+1

rfox90 commented 9 years ago

I'm also having trouble with this.

My main layout runs a subtemplate statically(Not using Template.dynamic) which has an autorun block which is being called. The template just doesn't update.

If I force a re-render in Blaze-Layout comment out line 78's conditional in layout.js then everything works.

Its part of an attempt by me to create a breadcrumb package compatible with FlowRouter. The Package's example application illustrates the problem:

https://github.com/rfox90/meteor-breadcrumb-plugin/tree/master/examples/basic

If I'm doing something dumb please let me know :)

:+1:

ryanbuiltthat commented 9 years ago

Sorry if I'm not understanding the breadcrumb issue but couldn't you just keep the breadcrumbs in a reactive var and render that? Wouldn't that reflect any route or URL state change?

rfox90 commented 9 years ago

I'm sorry but I doubt that would change things. I have a reactive template. Outside of blaze layout it works. My guess is any region sub templates have issues being reactive.

The documentation on Template.autorun should make the template act like a reactive var anyway and my autorun is firing.

However I'll put together an example with a reactive var as an experiment. I'll also add an example working breadcrumb to a separate route that doesn't use blaze layout.

Yeah reactive var doesn't work, Again console.logs proving its updating the reactive var: https://github.com/rfox90/meteor-breadcrumb-plugin/tree/reactive-var

rfox90 commented 9 years ago

I fixed my issue ignore me. :)

dearlordylord commented 9 years ago

+1 this

matikucharski commented 9 years ago

+1

markdowney commented 9 years ago

+1

nekkon commented 8 years ago

+1

nekkon commented 8 years ago

Any news on this one? Having a flag for forcing to re-render is something necessary. Please notify if this will be a future feature otherwise I will have to use another templating plugin..

SharadKumar commented 8 years ago

+1

I have the following:

authenticatedRoutes.route('/country/:slug', {
  name: 'country',
  action: (params, queryParams) => {
    BlazeLayout.render('default', {
      yield: 'country'
    });
  }
});

There is a list of countries generated on sidebar. On click, route (path) is changed but country template not fired (onCreated). I am using OnCreated to fetch latest country since route changed.

How to work around this? Is this change coming?

ryanbuiltthat commented 8 years ago

@SharadKumar this is how I handle those situations, the flow router guide has a great example.

https://kadira.io/academy/meteor-routing-guide/content/accessing-the-url-state

Tracker.autorun(function() {
    FlowRouter.watchPathChange();
    var context = FlowRouter.current();
    // use context to access the URL state
});

This autorun will rerun for every route or URL change in our app. We can access the URL state using FlowRouter.current().

This is what's inside that object:

{
    path: "/blog/meteor/hello-world?comments=yes",
    params: {category: "meteor", postId: "hello-world"},
    queryParams: {comments: "yes"}
    route: {name: "blogPost"}
}

So in short, use FlowRouter to monitor for the path change and wrap your logic in a tracker function, that'll keep it updated.

If anyone has a better way I'm open to hear it or suggestions on improvement. I'm still getting into FlowRouter myself so I'm hoping I have this understood correctly but it's working in my projects.

bySabi commented 8 years ago

I create a PR: https://github.com/kadirahq/blaze-layout/pull/53 for this. if is accepted we can call BlazeLayout.render this way:

BlazeLayout.render('mainLayout', {area: 'viewPersona'}, {force: true})
arunoda commented 8 years ago

For all these questions, force re-render is not the answer. You can always do things reactively. Adding force rendering feature would suggest users to do this often to sideaway from actual problems. Which leads to performance issues.

Therefore we are not taking this as a feature. Sorry guys.

ramezrafla commented 8 years ago

@arunoda, could you please explain how to handle reactively non-db data? I think this is the issue that is being addressed above, not subscription-based data.

e.g. we have a static menu (via template) and want to disable the 'back' button when the user clears his / her history. How do you add the 'disabled' class without having to use jQuery?

Thanks a lot! This page gets frequent redirection for those looking for re-rendering so your answer will help a lot of people.

ryanbuiltthat commented 8 years ago

I have had to utilize triggers for this and documentGetElementById but have noticed that I need to set a small delay sometimes as short as 50ms.

On Wed, Nov 18, 2015 at 9:53 AM, Ramez Rafla notifications@github.com wrote:

@arunoda https://github.com/arunoda, could you please explain how to handle reactively non-db data? e.g. we have a static menu (via template) and want to disable the 'back' button when the user clears his / her history. How do you add the 'disabled' class without having to use jQuery?

— Reply to this email directly or view it on GitHub https://github.com/kadirahq/blaze-layout/issues/21#issuecomment-157738439 .

ramezrafla commented 8 years ago

@ryanbuiltthat, your comment about the small delay (via setTimeout) was crucial for us as we were banging our heads against the wall, thanks a lot!

ryanbuiltthat commented 8 years ago

:) glad it helped! In my case I was adding a and removing a class to the body element. I was going nuts trying to figure out what was happening until, after paying very close attention to some breakpoints, I realized the triggers are very, very fast and if the DOM element isn't rendered yet the trigger never knows it's there. So now anytime I need to manipulate the DOM in any way via a trigger I just make it a habit of adding a tiny delay. Haven't had issues since and it doesn't appear to affect UX at all.

avalanche1 commented 8 years ago

I am having a somehow related issue with FastRender, I guess.. https://github.com/kadirahq/fast-render/issues/151

JuniorNunes7 commented 8 years ago

I used the function "BlazeLayout.reset()" before render template again and it's work fine.

davidjytang commented 7 years ago

Same situation with @kylestew . Now that @arunoda closed this. I guess if we have non-dynamic template with no db and no session, we still have to reload that template again on different route and start afresh.

Going with BlazeLayout.reset() route now.

Or maybe someone could share how to easily plug a static {{> someTemplate}} in rendered layout and retain all its current data on route change.

PersonaA commented 7 years ago

This hack helps me to reset reactive variable if router param have been changed:

Template.page.onCreated(function () {
  this.get_slug = () => FlowRouter.getParam('slug');
  this.get_good = () => Goods.findOne({slug: this.get_slug()});

  // Save slug
  let initial_slug = this.get_slug();

  this.reactive_var = new ReactiveVar(false);

  this.autorun(() => {
    if (initial_slug !== this.get_slug()) {
      this.reactive_var.set(false);

      // Update slug
      initial_slug = this.get_slug();
    }
  });
});
bradgreens commented 7 years ago

I used @JuniorNunes7 solution by resetting the layout in the route file. Worked great, feels dirty.

update: I take it back :-( seems this breaks other routing patterns. Will post back when I have the right fix

Went with the Tracker.autorun && FlowRouter.watchPathChange strategy. It works, though it requires to use onCreated as well for the initial state, so it feels like running 3 or 4 methods to complete a singular task.

focus97 commented 3 weeks ago

Not entirely sure my use-case is the same as others here, but it's similar enough so I'm posting this because others who came here like me may benefit.

In our Meteor app, we have page transitions that occur between any page/view. We do the transition based on the _uihooks feature. I.e.

Template.newViewInOut.onRendered(function(){
    this.firstNode.parentNode._uihooks = {      
        insertElement: function(node, next) {
                // do your UI logic

Our Templates look like so:

<template name="SomeTemplate">

    {{#newViewInOut}}
        <div>
            // tons of stuff to render 
        </div>
    {{/newViewInOut}}

</template>

But one of our Templates uses Blaze's dynamic params, so this particular template serves up many different page paths that all have different data. As users click through multiple "pages" that share the same Template, we no longer had the nice page transition. BlazeLayout.reset() just wasn't working for us (and perhaps that's due to me just not using it the way others are in this thread).

The fix for us was to just pretend that there are multiple things we want to render and use an {{#each}} loop.

When a user lands on the route using this Template, we get the param let path = FlowRouter.getParam('page_path'); and store it in a Session within Template.onRendered. I.e. Session.set('hackThingy', [path]);

Then we .watchPathChange() in .autorun, and if we indeed have a new path, we set the Session var with the new path (not add to the array, but replace its contents so there's only one item).

We then have a helper to loop over the contents of the Session var, but without outputting anything. (Helper is named the same as the Session var.)

<template name="SomeTemplate">
    {{#each hackThingy }}
    {{#newViewInOut}}
        <div>
            // tons of stuff to render 
        </div>
    {{/newViewInOut}}
    {{/each}}

</template>

Works great for us! And this approach also avoids re-running all the onCreated, onDestroyed, etc. Hope it helps someone else.