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);
},
});
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
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 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;
},
});
thank you for the previous answer, it was not that clear to me though and I continue to follow my approach and using events on each step to capture the input data. I was wondering though how can I show up an alert at each step when not all the fields are filled in and keep the current template displayed and not moving on to the next page/template?
I am trying using this but does not work
'click #NextPart': async function (event, instance){
event.preventDefault();
options = {
"x_value": parseInt($('input[name="x_value"]:checked').val()),
"y_value": parseInt($('#y_value').val()),
"b_value": parseInt($('input[name="b_value"]:checked').val()),
};
Session.set('options',options)
console.log('current stepTemplate ',stepTemplate)
answers=Session.get('options')
console.log('answers',answers)
if (answers!==null) {
Object.keys(answers).forEach(function (key) {
console.log('options loop key',answers[key])
if ((answers[key]==4) || isNaN(answers[key])){
console.log('problem here fill in all!!')
swal({
title:"Please fill all the required fields!"
});
stepTemplate='stepTwo'///set the current template to the same to prevent moving to the next one
console.log('check again stepTemplate',stepTemplate)
}
});
}
}
Instead of a Session I would simply store the values in the instance. Where is stepTemplate coming from? That should be something reactive. Your code doesn’t seem to write the changed stepTemplate back to where it could be interpreted by blaze to perform any kind of action (ReactiveVar).
Hi,
I apologize for all these questions but I am not that familiar with meteor.
regarding the instance I assume is the same advice you have given me in previous post, but did not get it. I will provide an example of how I currently do it (the wrong way) and hopefully you can tell me how I can fix it and keep these values in instance instead of Session.
The html of the dynamic template ‘stepTwo’ looks similar to this:
and each dynamic template has a lot of radio, check buttons which I need to keep every time they are filled in, and before leave the template to move on to the next by selecting the button nextstep , a check that all the fields were filled in should be done
I encountered a problem only in Firefox though when loading last template (which is the longest page)the page is by default scrolled down, so the user should always scroll up when reaches this template/page/view
I have tried
well after some more testing I put it inside the events of the overall template, since in the onclick of the button of each page/nested template(stepOne, stepTwo etc) the next page is loaded
Template.experiment.events({
'click .btn-lg': async function (event, instance) {
event.preventDefault();
window.scrollTo(0,0);
the only thing is that at times I observe some quick scrolling up before it changes…
I tried also to apply this window.scrollTo(0,0);
on the last step onrendered but with no result
I suppose this is because the majority of the functionality of all pages is gathered within the overall template in which all the steps/pages are included.