How do i pass the value calculated from autoform autovalue reactively?


#1

Hi,
I have this sample code that calculated age based on birthdate input using autoform:
temaplate:

<head>
  <title>Calculate age</title>
</head>

<body>
  {{> form}}
</body>

<template name="form">
    {{> quickForm fields='birthdate,myAge' collection="Age" id="insertAgeForm" type='insert' buttonContent="Calculate Age"}}
</template>

Schema:

Age = new Meteor.Collection("age");

Age.attachSchema(new SimpleSchema ({
  birthdate: {
      type: Date,
      label: "Birthday",
      optional: true,
      autoform: {
        type: 'bootstrap-datepicker'
      }

  },
  myAge: {
      type: Number,
      label: "My Age",
      optional: true,
  },
  ageCompute: {
      type: Number,
      optional: false,
      decimal: true,
      autoValue:function(){
        var dayBirth = this.siblingField("birthdate").value;
        var age =moment().diff(moment(dayBirth, 'MM/DD/YYYY'), 'years');
          console.log(age);
          return age;
      }
  }
}));

The function is working on the console but I don’t know the approach on how to pass the value to the sibling field myAge.

What is the best way to reactively pass the value of the age function to the sibling field?

For example when the user pick the date of his birthday on the datepicker, it reactively pass the value to myAge field without triggering an event, in this way, the user will see his age immediately.

Any help will greatly appreciate!

Thanks,


#2

No need to have a special field for the autovalues, you just use them on the field that you want them to be.

Age.attachSchema(new SimpleSchema ({
  birthdate: {
      type: Date,
      label: "Birthday",
      optional: true,
      autoform: {
        type: 'bootstrap-datepicker'
      }
  },
  myAge: {
      type: Number,
      label: "My Age",
      optional: true,
      autoValue:function(){
          var dayBirth = this.siblingField("birthdate").value;
          var age = moment().diff(moment(dayBirth, 'MM/DD/YYYY'), 'years');
          return age;
      }
  },
}));

#3

Thanks @copleykj!

It works when the form is submitted. :smile:

How about when the user pick a date, it immediately calculate the age then the calculated value will display in myAge input field?


#4

From a UX standpoint I would say not to include the extra field since user knows their age. However if there is some special purpose then it’s likely you will need to hand code this into the events on the from.


#5

I already removed the extra fields and implemented your approach, which is working perfectly.

This is only a sample use case, I will be implementing this to my actual project, the actual use case is the user is not the main subject of the form, the data will be coming from a hard copy form (customer form) which will be transferred into the system, it make sense to offer them a mechanism to automate the value of a certain field like the age and they immediately see the results, so that they can move on to another input field, in this way, we can minimize typo error or wrong data entry.


#6

Yes, in that case you’ll likely need to code a change even on the field and update the value of the other field manually.


#7

I still have no idea how to do this. :expressionless:

Thanks @copleykj!


#8

Actually, the validation works upon submission when I set a maximum value but the problem is how to display the value on the input field without triggering an event.


#9

I believe you should be able to add this as a change event on the field at the template level and it should work.

Template.templateName.events({
    'change input[name=birthdate]': function(event, template){
        var birthdate = $(event.target).val()
        template.$("input[name=myAge]").val(birthdate);
    }
});

#10

It didn’t work :frowning:

Thanks @copleykj!


#11

If you have a repository that I could look at I’d be willing to take a look and see if I could get it working for you.


#12

Hi @copleykj!

Thank you for the help! Here’s the sample repo.


#13
Template.form.events({
  'change input[name=birthdate]': function(event, template){
    var birthdate = $(event.target).val();
    template.$('input[name=myAge]').val(moment().diff(moment(birthdate, 'MM/DD/YYYY'), 'years') || "");
  }
});

#14

It works! :smile:

But there’s an error when i clicked the button to submit.

Error: Method not found [404]

I think i should include a click method.

Thanks for the help @copleykj!


#15

This is because your shema.js is defined only on the client and your shema and collection are not available on the server. Moving this file into shared space will fix the error.


#16

oh, my bad, I’ve overlooked that details.

Thanks again @copleykj! :smile:


#17

Hi @copleykj,

I have one last question relative to this topic. What is the best approach on multiple change events?

I have several age calculation within my form, the code above works perfectly but if I add another change event replacing

change input[name=birthdate] to input[name=children.birthdate]

same function but with different target fields, the code doesn’t work, does creating multiple

$('body').on('change', selector1); 
$('body').on('change', selector2);

is the best way to achieve same result?


#18

You can register the event just the same, but in the case of an attribute selector with a period in the value, you will need to quote the value.

Template.form.events({
  //notice the "'s around children.birthdate
  'change input[name="children.birthdate"]': function(event, template){
    //code
  }
});

#19

I’ve tried your suggestion but it’s not working, here’s my schema

children: {
      type: Array,
      optional: true,
    },
    'children.$': {
      type: Object,
      optional: true,
      autoform: {
        afFormGroup: {
          'formgroup-class': 'col-xs-6 col-sm-4'
        }
      }
    },
    'children.$.name': {
      type: String,
      label: "Child Name",
      optional: true,
      autoform: {
        afFormGroup: {
          'formgroup-class': 'col-xs-6 col-sm-4'
        }
      }
    },
    'children.$.birthdate': {
      type: Date,
      label: "Child Birthdate",
      optional: true,
      autoform: {
        type: "bootstrap-datepicker",
        afFormGroup: {
          'formgroup-class': 'col-xs-6 col-sm-4'
        }
      }
    },
    'children.$.age': {
      type: Number,
      label: "Age of Child",
      optional: true,
      min: 1,
      max: 22,
      autoform: {
        afFormGroup: {
          'formgroup-class': 'col-xs-6 col-sm-4'
        }
      }
    },

I use autoform and simpleSchema to generate my form.

I’ve tried children.$.birthdate also to no avail.

only the first change event is working.

here’s my code:

'change input[name=birthdate]': function(event, template){
    var birthdate = $(event.target).val();
    template.$('input[name=ageOfEnrollee]').val(moment().diff(moment(birthdate, 'MM/DD/YYYY'), 'years') || "");
  },
  'change input[name="children.birthdate"]': function(event, template){
    var childbirthdate = $(event.target).val();
    template.$('input[name="children.age"]').val(moment().diff(moment(childbirthdate, 'MM/DD/YYYY'), 'years') || "");
  }

Actually, i have other fields that will use this event. Parents, Siblings and Spouse age.


#20

You will have to look at the rendered form and see the attributes that it generates.