Meteor: Custom AutoForm with array of objects in afEachArrayItem blocks - meteor

I'm working on dictionary app, and schema have a nested structure.
articles (collection)
-words (array of objects {"note", "word"} )
-translations (array of objects {"translation", "examples"} )
--examples (array of objects {"example", "translation"} ) that means
examples of word usage with it's translation.
The {{> quickForm collection=articles ... }} are working fine, but I want to change template and functionality by some conditions...
I tried to use
{{#autoForm collection=articles id="insertArticleForm" class="article-form" }}
{{#afEachArrayItem name='words'}}
{{> afFieldInput name=this.current.note placeholder='schemaLabel' class="note"}}
{{> afFieldInput name=this.current.word placeholder='schemaLabel' class="word"}}
<button type="button" class="autoform-remove-item"><span class="glyphicon glyphicon-remove"></span></button>
{{/afEachArrayItem}}
<button type="button" class="autoform-add-item" data-autoform-field="words"><span class="glyphicon glyphicon-plus"></span></button>
{{/autoForm}}
But it doesn't work.
It looks like this old issue: Meteor: Custom AutoForm with array of objects
but it seems after some recent updates of Meteor/Autoform, this syntax doesn't work.... and author of plugin doesn't answer on issues for months (
When I changed {{> afFieldInput name=this.current.note }} to {{> afFieldInput name='words.$.note' }} it seems like working , form appears with all need fields, but nothing are submit on the server. Even in this simple example, without nested fields...

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}}

How to create reusable UI with variable template?

I want to do something like this:
Component file:
<template name="drop_down">
<span class="dropdown">
{{> primary_element}} <--- load the template named button
<span class="dropdown-panel">
{{> panel_template}} <--- load the template named button_panel
</span>
</span>
</template>
Usage:
{{> drop_down primary_element="button" panel_template="button_panel"}}
<template name="button"> some styled button </template>
<template name="button_panel"> panel content </template>
and then I can reuse it just like this
{{> drop_down primary_element="tmp_btn_2" panel_template="tmp_panel_2"}}
<template name="tmp_btn_2"> another button style </template>
<template name="tmp_panel_2"> other panel content </template>
You should be able to do this with dynamic templates. In blaze you can pass in the template to be used as a variable, as well as the data context itself. They are quite flexible.
For example:
{{> Template.dynamic template=whichTemplate data=myData }}
This would refer to the whichTemplate helper to figure out which template to use and would get the data context from the myData helper. i.e. both the choice of template and the choice of data come from variables.
In your case you are trying to use two dynamic templates in the context of your dropdown template. You can do:
<template name="drop_down">
{{#with myElements}}
<span class="dropdown">
{{> Template.dynamic template=this.primary}}
<span class="dropdown-panel">
{{> Template.dynamic template=this.panel}}
</span>
</span>
{{/with}}
</template
Then your myElements helper just needs to return the names of the templates to use as strings, ex:
Template.dropdown.helpers({
myElements() {
let p1 = "button"; // compute these two based on your own logic
let p2 = "button_panel";
return {primary: p1, panel: p2 };
}
});

How can I avoid duplicate templates in Meteor?

So I'm building my first app with meteor, and I feel like I'm repeating myself with my templates more than I should be.
I have multiple parent views, an example of which is the user contacts view, and the add group members view. (simplified examples below.)
<template name="GroupMembers">
{{#each contacts}}
{{> contact }}
{{/each}}
</template>
<template name="contacts">
{{#each contacts}}
{{> contact }}
{{/each}}
</template>
<template name="contact">
//... single contact template stuff
</template>
When the contact is displayed in the contacts list, I want to display a remove from contacts link in the single contact template, but in the group members list I'd like an 'add to group' link in its place. I know I could probably achieve this with either session variables or by invoking the iron-router controller obj, but I'd like to know if there is a simple way to do this in the template helper(s). Or put another way can these template partials become context aware?
Any help would be great.
Thanks.
I would solve it this way:
<template name="GroupMembers">
{{#each contacts}}
{{> contact groupMembers=true}}
{{/each}}
</template>
<template name="contacts">
{{#each contacts}}
{{> contact }}
{{/each}}
</template>
<template name="contact">
<p>
{{#if groupMembers}}
{{../name}}
<button>add to group</button>
{{else}}
{{name}}
<button>delete</button>
{{/if}}
</p>
</template>
Live demo: http://meteorpad.com/pad/LDTvHC787kJ6e9JQA/Leaderboard

Comparing current user to a meteor list

I'm currently making a simple web app with meteor.js . I'm trying to implement a simple feature for my fantasy football league's custom site that I'm building.
Here's my code that's not working.
{{#each users}}
{{#if Meteor.userId() {{_id}} }}
{{> ownTradingBlock}}
{{else}}
{{> userTradingBlock}}
{{/if}}
{{/each}}
So basically I want to render a different template if the user in the list of league members is the current user that is logged in. Does anybody have any thoughts on how this is creating an error, and/or if there's a better way to do it?
Here's the error code I'm getting.
.html:67 : expected space
You cannot use a Meteor method within Spacebars. For this you will need to create a helper:
Template.yourTemplate.helpers({
isEq: function (id) {
if (Meteor.userId() === id)
return true;
return false;
}
});
Then in your template:
{{#each users}}
{{#if isEq _id}} }}
{{> ownTradingBlock}}
{{else}}
{{> userTradingBlock}}
{{/if}}
{{/each}}

How to render a Meteor Template from Collection of Template names?

I have three simple Templates in Meteor, and a Collection on the server with any combination of their names. I want to be able to render these templates dynamically based on which of their names are in the Collection.
Currently I am trying to accomplish this by using the client to subscribe to the Collection, and access the names through a template function. Unfortunately, if I try to run ">" on the names, Meteor attempts to render the variable name instead of the Template pointed to by its value.
So instead of rendering the html in template1, template2, and template3, the output is merely their names on the page: "template1 template2 template3".
Here is the code I've been using, I hope there's a way to solve my issue without having to run Meteor.render manually.
Server js:
TemplatesToRender = new Meteor.Collection("templatesToRender");
TemplatesToRender.insert({templateName: "template3"});
TemplatesToRender.insert({templateName: "template2"});
Client html:
<body>
{{#each templatesToRender}}
{{> templateName}} // meteor trying to render a template
// called "templateName" instead of the
// variable inside templateName.
{{/each}}
</body>
<template name="template1">
<span>Template 1</span>
</template>
<template name="template2">
<span>Template 2</span>
</template>
<template name="template3">
<span>Template 3</span>
</template>
You can make a render helper:
Handlebars.registerHelper('render', function(name, options) {
if (Template[name])
return new Handlebars.SafeString(Template[name]());
});
And use it with
{{render templateName}}
You might want to try this
in your html
<body>
{{> templateToRender}}
</body>
<template name="templateToRender">
{{! use below to detect which template to render}}
{{#if templateName "template1"}}
{{> template1}}
{{/if}}
{{#if templateName "template2"}}
{{> template3}}
{{/if}}
{{#if templateName "template3"}}
{{> template3}}
{{/if}}
</template
<template name="template1">
<p>this is template1</p>
</template>
<template name="template2">
<p>this is template2</p>
</template>
<template name="template3">
<p>this is template3</p>
</template>
in your script
Template.templateToRender.templateName = (which) ->
# if user have a field like templateName you can do things like
tmplName = Meteor.user().templateName
# Session.equals will cause a template render if condition is true.
Session.equals which, tmplName
Meteor 1.0 just came out today, and I just want to update this for 2014 :)
https://docs.meteor.com/#/full/template_dynamic
{{> Template.dynamic template=template [data=data] }}
Sample Usage:
{{#each kitten}}
{{> Template.dynamic template=kitten_type data=this }}
{{/each}}

Resources