Meteor Autoform update a nested collection - meteor

I'm trying to create a form in order to insert a new element inside a nested array in a collection.
Here are my schemas :
Schemas.CampaignsSchema = new SimpleSchema({
'name': {
type: String
}
});
​
Schemas.ElectionsSchema = new SimpleSchema({
'campaigns': {
type: [Schemas.CampaignsSchema],
defaultValue: []
}
});
Here is my template :
Template.campaignsNew.helpers({
schema() { return Schemas.CampaignsSchema; },
});
​
​
<template name="campaignsNew">
{{#autoForm
collection='Elections'
schema=schema
doc=doc
scope='campaigns'
id='insertCampaignForm'
type='update-pushArray'}}
<fieldset>
<legend>Add a Campaign</legend>
{{> afQuickField name='campaigns.$.name'}}
</fieldset>
<button type="submit" class="btn btn-primary">Insert</button>
{{/autoForm}}
</template>
So a field is generated by autoform but nothing happens when I hit submit.
If I enable Autoform.debug() I got :
SimpleSchema.clean: filtered out value that would have affected key "campaigns", which is not allowed by the schema
SimpleSchema.clean: filtered out value that would have affected key "campaigns.$", which is not allowed by the schema
SimpleSchema.clean: filtered out value that would have affected key "campaigns.$.name", which is not allowed by the schema
Does someone have any idea?

It seems that the schema attribute of #autoform doesn't work with the type update-pushArray.
Here is the template that works with the reste of the code :
<template name="campaignsNew">
{{#autoForm
collection='Elections'
doc=election
id='insertCampaignForm'
type='update-pushArray'
scope='campaigns'}}
<fieldset>
<legend>Add a Campaign</legend>
{{> afQuickField name='name'}}
</fieldset>
<button type="submit" class="btn btn-primary">Insert</button>
{{/autoForm}}
</template>
The only issue is that the name field is pre-filled with the Election name...
It seems that your nested document mustn't have a field with the same name as the main document.
Yet the created nested document has the good name and the main document's name remain unchanged.

Related

Meteor change collection on user dropdown selection

I'm using Meteor in combination with autoForm / quickForm. I have on collection, lets call it "Sports" for this example. The collection asks the question which sports the user has done this week using a dropdown (allowedValues in autoForm). Now if the user selects running, I want to show 'distance', 'area', etc. If the user selects basketball, I might want to show 'shots taken', etc.
How should I go about this? Create multiple Collections or SimpleSchema's, or is there a different preferred approach? Could not find anything on Google, though I am sure this is not an uncommon question. If anyone has a link with more info that is already very much appreciated.
Update:
I am using an 'each' loop to loop through all possible sports I have defined earlier. Do you think it would make more sense to create a form item for each different sport? If so, how can I make sure this is correctly configured in the schema? Thank you in advance!
{{#autoForm collection="Sports" type="update" doc=this id="FieldValueIsForm"}}
{{#each sports}}
<h3>{{this.name}}</h3>
{{> afQuickField name="sports.$.sportTrue" noselect=true }}
{{#if afFieldValueIs name="sports.$.sportTrue" value=true}}
{{> afQuickField name="sports.$.sportDistance" value=this.frequency}}
{{/if}}
{{/each}}
<div>
<button type="submit">Submit</button>
</div>
{{/autoForm}}
Update 2:
My schema can be found here: http://pastebin.com/SbBSbqW2
I simplified it a bit, but this is the main content. For different sports I would need different input fields.
Sounds like you want to use the afQuickField option with a conditional. The documentation talks about it here. There is also a demo of what the code should look like here; however, it looks like this:
{{#autoForm collection="FieldValueIs" type="insert" id="FieldValueIsForm"}}
{{> afQuickField name="a" options="allowed" noselect=true}}
{{#if afFieldValueIs name="a" value="foo"}}
{{> afQuickField name="b"}}
{{/if}}
{{/autoForm}}
You would just need to make sure you set up "a" and "b" to be the select fields you want by setting them up properly in your schema.
UPDATE:
I assume you want to store the distance, shots taken, etc. in the SingleSport collection. Exactly how you store it is up to you, but it could look something like the following:
SingleSport = new SimpleSchema({
sportType: {
type: String
},
distanceRun: {
type: Number,
decimal: true,
optional: true
},
shotsTaken: {
type: Number,
optional: true
},
sportTrue: {
type: Boolean,
label: "Sport completed",
autoform:{
type: "boolean-radios",
trueLabel: "Enabled",
falseLabel: "Disabled",
value: false
}
}
});
Then, you could change the conditional section of your form like so:
{{#if afFieldValueIs name="sportType" value="running"}}
{{> afQuickField name="distanceRun"}}
{{/if}}
{{#if afFieldValueIs name="sportType" value="basketball"}}
{{> afQuickField name="shotsTaken"}}
{{/if}}

Form doesn't get individual form ID

I have an {{each}} statement which is suppose to have a form in. I can't figure out why the form doesn't use the forms unique _id. Any suggestions?
Path: helper.js
Template.Offer.helpers({
jobOffers: function () {
return JobOffers.find({candidateUserId: Meteor.userId()});
},
makeUniqueID: function () {
return this._id;
}
});
Path: template.html
{{#each jobOffers}}
{{#autoForm collection="JobOffers" id="makeUniqueID" doc=this type="update"}}
{{> afQuickField name='offer'}}
<button type="submit" class="btn btn-primary submit">Update</button>
{{/autoForm}}
{{/each}}
With
id="makeUniqueId"
you make the form have id equal to exactly the string "makeUniqueId". To generate new IDs, omit quotes:
id=makeUniqueId
This will tell Spacebars to evaluate the function that stays behind the makeUniqueId helper, therefore supplying the autoForm template with proper value for id parameter.

Meteor Error: Missing required parameters on path The missing params are: ["_id"]. The params object passed in was: {}

I have this in my routes:
Router.map(function() {
...
this.route('studentEdit', {
path: '/student/:_id/edit',
data: function() {
return Students.findOne(this.params._id);
},
});
this.route('studentDetail', {
path: '/student/:_id',
data: function() {
return Students.findOne(this.params._id);
}
});
...
});
And I have this in my template using autoform:
{{#autoForm collection="Students" id="studentEdit" doc=this type="update"}}
{{> afQuickField name='name'}}
{{> afQuickField name='phone'}}
{{> afQuickField name='address' rows=6}}
{{> afQuickField name='remarks' rows=6}}
<button type="submit" class="btn waves-effect waves-light"><i class="material-icons">save</i></button>
{{/autoForm}}
The edit page loads fine, with the prepopulated fields. And when I save, it does save, yet, it doesn't redirect to the detail page, and returns this error in console:
Exception in delivering result of invoking '/students/update': Error: Missing required parameters on path "/student/:_id". The missing params are: ["_id"]. The params object passed in was: {}.
UPDATE
Routing to the detail page now works, yet the error still exist in the console. I must be missing something. This is what I've done to get it working for the time being:
var moveOnRouter = {
onSuccess: function(formType, result) {
Router.go('studentDetail', {_id: this.docId});
}
}
AutoForm.addHooks('studentEdit', moveOnRouter);
You need to explicitly go to the other route on submit from your form. But since your button is a submit you also need to prevent the default submit action.
With template events you'd do something like:
Template.myTemplate.events({
'submit .btn'(ev) {
ev.preventDefault();
router.go('studentDetail',{ _id: this.docId });
}
});
But since you're hooking autoform perhaps it's easier just to remove the type="submit" from your button definition.

Meteor Users: add user by admin user only

I'm using the useraccounts package in my Meteor app. I want an admin to be able to add a new user (and disable signing up through the frontend). Therefore, I have added a Collection with a SimpleSchema as per the suggestion of meteor-collection2. I'm alos using AutoForm to create an 'Add user' page.
<template name="addCustomerProfile">
<div class="container">
<h1>Edit document</h1>
{{#if isReady 'updateCustomerProfile'}}
{{#autoForm collection="Users" id="userForm" type="insert" }}
<fieldset>
{{> afQuickField name='emails.0.address'}}
{{> afQuickField name='emails.0.verified'}}
{{> afQuickField name='services.password'}}
{{> afQuickField name='username'}}
{{> afQuickField name='profile.firstName'}}
</fieldset>
<button type="submit" class="btn btn-primary">Add User</button>
{{/autoForm}}
{{else}}
Nothing
{{/if}}
</div>
</template>
I can add users whenever the 'services.password' is not added to the form, but obviously no default password is set for the user in the Mongo database in that case. How can I add a field so the admin can set a default password for that user (which the user will then be able to change later on).
Why not just forbidClientAccountCreation and sendEnrollmentEmail?
Accounts.config({
forbidClientAccountCreation: true
});
Meteor.methods({
'inviteUser': function (doc) {
check(doc, YourForm);
let userId = Accounts.createUser(doc);
Accounts.sendEnrollmentEmail(userId);
}
});

Meteor get ID of template parent

I have two Collection : a collection A which include array of B ids.
Template A :
<template name="templateA">
Name : {{name}} - {{_id}}
{{#each allBsOfThisA}}
{{> Bdetail}}
{{/each}}
Add B for this A
</template>
Note : in this templateA, I list all A and their detail informations. At bottom of the A, I putted a link to add a B.
Template of Bsubmit :
<div class="form-group {{errorClass 'nameOfB'}}">
<label class="control-label" for="nameOfB">nameOfB</label>
<div class="controls">
<input name="nameOfB" id="nameOfB" type="text" value="" placeholder="nameOfB" class="form-control"/>
<span class="help-block">{{errorMessage 'nameOfB'}}</span>
</div>
</div>
<input type="submit" value="Submit" class="btn btn-primary"/>
On the Bsubmit script : I want to get the ID of A. I tried with template.data._id but it's not working :
Template.Bsubmit.events({'submit form': function(e, template) {
e.preventDefault();
console.log("template.data._id: " + template.data._id);
var B = {
name: $(e.target).find('[name=name]').val(),
AId : template.data._id
};
}
});
EDIT :
BSubmit's iron-router part :
Router.route('Bsubmit ', {name: 'Bsubmit '});
Neither the template nor the route does know about the A-instance of the other template/route.
So one solution would be to pass the id to the route, which allows you to fetch the instance or use the id directly:
Template:
<template name="templateA">
Name : {{name}} - {{_id}}
{{#each allBsOfThisA}}
{{> Bdetail}}
{{/each}}
Add B for this A
</template>
Route:
More information about passing arguments to a route
Router.route('/Bsubmit/:_id', function () {
var a = A.findOne({_id: this.params._id});
this.render('Bsubmit', {data: a});
});
Then you could use template.data._id in the event.
Another solution would be to embed the form into the other view, so you can access the data of the parent template in there (documentation of parentData).

Resources