Use same url but load different pages/screens

Hello,
I am building a survey with meteor in the style of https://www.typeform.com/templates/t/self-evaluation/
that means that I have just one url where my survey will be routed

e.g. /experiment

and after each step(clicking buttons , answering to questions) a new page (meaning just one new question) will be loaded but within same url (/experiment) and not new or load the template in the end of the same page.
How can I manage to do this without creating multiple pages (html and js) and append them each time to different urls within FlowRouter but just use one? Also I just tried using separate templates html files within the main template/html file but still it just adds new template in the bottom of the page and not loading a new page
thank you in advance

You could use {{>Template.dynamic template=stepTemplate data=stepData}} in the template for /experiment', wherestepTemplate` is a ReactiveVar that will contain the template names for the different steps. Here is an extremely simplified example how this could work (just edited a bit to make all parts play better)

Template.experiment.onCreated(function () {
  const instance = this;
  instance.step = new ReactiveVar('stepOne');
  instance.steps = {
    stepOne: {
      nextStep: 'stepTwo',
      title: 'Next Step',
      message: '<h2>This is the 1st step</h2>',
    },
    stepTwo: {
      nextStep: 'stepThree',
      title: 'One more Step',
      message: '<h2>This is the 2nd step</h2>',
    },
    stepThree: {
      message: '<h2>You did it, you finished all steps</h2>',
    },
  };
});
Template.experiment.helpers({
  stepTemplate() {
    return Template.instance().step.get();
  },
  stepData() {
    const instance = Template.instance();
    var step = instance.steps[instance.step.get()];
    // return the data the step template should receive
    return step;
  },
});
Template.experiment.events({
  'click button'(event, instance) {
    var nextStep = event.currentTarget.dataset.nextStep;
    instance.step.set(nextStep);
  },
});

And the templates could be

<template name="experiment">
 {{>Template.dynamic template=stepTemplate data=stepData}}
</template>
<template name="stepOne">
 <h1>Step One</h1>
  {{{message}}}
 {{#if nextStep}} <button data-next-step="{{nextStep}}">{{title}}</button>{{/if}}
</template>
<template name="stepTwo">
 <h1>Step Two</h1>
 {{{message}}}
 {{#if nextStep}} <button data-next-step="{{nextStep}}">{{title}}</button>{{/if}}
</template>
<template name="stepThree">
 <h1>Step Three</h1>
  {{{message}}}
 {{#if nextStep}} <button data-next-step="{{nextStep}}">{{title}}</button>{{/if}}
</template>
2 Likes

Thank you so much for your instant help this is what I need to do :slight_smile:
I run your example and I m working on my project the way you suggested!

May I ask one more question, inside each step (page) I have radio buttons, dropbox lists which are filled one at a step by the user, what is the best way to catch the user input per template in an object and end up in an object containing all the user input given lets say three steps/pages?
I tried doing it within the

Template.experiment.events({
  'click button'(event, instance) {
    var nextStep = event.currentTarget.dataset.nextStep;
    instance.step.set(nextStep);
 options = {
            "question_1": $('input[name="question_1"]:checked').val(),
            "question_2": $('#question_2').val(),
  },
});

but is seems as it gets empty each time a new template is loaded so best way to do it is i believe use new reactive instances and create
Template.stepOne.events {()}
Template.stepTwo.events {()}

where I collect the feedback, am I right?

You’ll just need to pass whatever you choose to the next template. I used the explicit data context

<template name="experiment">
  {{>Template.dynamic template=stepTemplate data=stepData}}
</template>

where I have a helper stepData that provides the required data for each step. Each step could save stuff into a global variable that gets passed to the next template

@jamgold Thanks once more!
Can you please provide an example?
What I am doing currently is that inside the click button’(event, instance) event, where each time a button is selected to continue to next step/template, I have created a variable options where I am saving input from each template by checking each time in which stepTemplate the step is. I get what I need but is there any other more convenient way I did not catch?

  Template.maas_experiment.events({
        'click button'(event, instance) {
          var nextStep = event.currentTarget.dataset.nextStep;
          instance.step.set(nextStep);
          stepTemplate=Template.instance().step.get()


          if (stepTemplate=='stepThree' ){

            options = {
              "question_1": $('input[name="question_1"]:checked').val(),
              "question_2": $('#question_2').val(),
}
}
if (stepTemplate=='stepFour' ){

            console.log('we are here stepFour options', options)

            var question_3=parseInt($('input[name="question_3"]:checked').val());
            var question_4=parseInt($('input[name="question_4"]:checked').val());

          options.question_3=question_3
          options.question_4=question_4

}``

There are so many ways this could be done. I experimented a bit more with this and found the following to be a more generic solution. I’m sure someone could come up with a better one, however

Template.experiment.onCreated(function () {
  const instance = this;
  instance.step = new ReactiveVar('stepOne');
  instance.steps = {
    // place to collect form data from different steps
    formData:{
    },
    stepOne: {
      nextStep: 'stepTwo',
      title: 'Next Step',
      message: '<h2>This is the 1st step</h2>',
      waitForAction: new ReactiveVar(true),
      fruitRadioLabel: 'most',
      fruitRadioName: 'mostFruit',
    },
    stepTwo: {
      nextStep: 'stepThree',
      title: 'One more Step',
      message: '<h2>This is the 2nd step</h2>',
      waitForAction: new ReactiveVar(true),
      fruitRadioLabel: 'second',
      fruitRadioName: 'secondFruit',
    },
    stepThree: {
      message: '<h2>You did it, you finished all steps</h2>',
      // startOver: 'stepOne',
    },
  };
});

In the event handler for my step button I check for form data. I created a my own template that renders the Next button and pass in parent information so it is available in instance.data

Template.templateWithForm.events({
  'change input'(event, instance) {
    var step = instance.data.step.get();
    var currentStep = instance.data.steps[step];
    var nextStep = instance.data.steps[currentStep.nextStep];
    var formData = instance.data.steps.formData;
    if ('waitForAction' in currentStep) currentStep.waitForAction.set(false);
    formData[event.currentTarget.name] = event.currentTarget.value;
  },
});