I need to write a custom handlebar helper that checks query params an either shows a field, or doesn't depending.
Unfortunately it's returning true or false to the view and outputting it, instead of evaluating true and showing the fields inside the if, or false and not showing anything.
Any help is very welcome.
{{#sortedByDeals}}
<span class="deal-percentage">( {{ percent_off }} % OFF ds: {{ deal_score }})</span>
{{/sortedByDeals}}
Handlebars.registerHelper('sortedByDeals', function() {
console.log("helper method called")
var sortBy = getURLParameter('sort_by');
if(sortBy === "deals") {
console.log("true")
return true
} else {
return false
}
});
Answered my own, by reading the docs more http://handlebarsjs.com/block_helpers.html#conditionals.
Handlebars.registerHelper('if', function(conditional, options) {
// console.log("helper method called")
console.log(conditional)
var sortBy = getURLParameter('sort_by');
if(sortBy === "deals") {
// console.log("true")
return options.fn(this);
} else {
// console.log("else")
return options.inverse(this);
}
});
and in the template
{{#if sortedByDeals}}
<span class="deal-percentage">( {{ percent_off }} % OFF ds: {{ deal_score }})</span>
{{/if}}
Basic block helper will work without using conditional helper. See more here
Handlebars.registerHelper('sortedByDeals', function() {
console.log("helper method called")
var sortBy = getURLParameter('sort_by');
if(sortBy === "deals") {
return options.fn(this);
}else {
return options.inverse(this);
}
});
In template,
{#sortedByDeals}}
<span class="deal-percentage">...</span>
{{/sortedByDeals}}
Related
I have a SimpleSchema instance with two fields:
isApproved: {
type: Boolean,
defaultValue: false
},
impactedSystems: {
type: String,
optional: true
}
I'd like to change the optional attribute of impactedSystems to false if isApproved is set to true.
I've tried following the instructions in the docs but I can't get it to work. It suggests I add a custom function to impactedSystems like so (modified with my field names):
custom: function () {
var shouldBeRequired = this.field('isApproved').value == 1;
if (shouldBeRequired) {
// inserts
if (!this.operator) {
if (!this.isSet || this.value === null || this.value === "") return "required";
}
// updates
else if (this.isSet) {
if (this.operator === "$set" && this.value === null || this.value === "") return "required";
if (this.operator === "$unset") return "required";
if (this.operator === "$rename") return "required";
}
}
}
The field stays optional whether isApproved is true or not.
I also tried the code from this answer but the value of optional doesn't change when the field it depends on (isApproved) is updated.
How can I have the value of optional become the opposite of another boolean type field?!
Try this code. it is admittedly a little convoluted...
This is a generic helper you can use across all your schemas:
// This helper method does the ceremony around SimpleSchema's requirements
export const isRequired = (thing,shouldBeRequired) => {
if (shouldBeRequired) {
// inserts
if (!thing.operator) {
if (!thing.isSet || thing.value === null || thing.value === "") return "required";
}
// updates
else if (thing.isSet) {
if (thing.operator === "$set" && thing.value === null || thing.value === "") return "required";
if (thing.operator === "$unset") return "required";
if (thing.operator === "$rename") return "required";
}
}
};
In the schema itself you can do it like this:
const isRequiredWhenApproved = (record) => {
const shouldBeRequired = (record.field('isApproved').value);
return isRequired(record, shouldBeRequired);
};
isApproved: {
type: Boolean,
defaultValue: false
},
impactedSystems: {
type: String,
optional: true,
custom() {
return isRequiredWhenApproved(this);
},
},
I hope that works for you
I finally figured it out. I was inserting isApproved from one form and then updating impactedSystems in another. All I had to do was include isApproved (with type=hidden) in the update form where I want its value to be read. The code I provided is correct.
Example
{#autoForm collection=Requests doc=this id="singleRequestLayout" type="update"}} //This can also be of type insert
{{> afQuickField name="isApproved" type="hidden"}}
{{> afQuickField name="impactedSystems"}}
<button type="submit" class="button">Submit</button>
{{/autoForm}}
How to publish single objects seems not clear enough to me. Please what's the best way to handle this. This code snippet does not display anything on the view.
Helper file
singleSchool: function () {
if (Meteor.userId()) {
let myslug = FlowRouter.getParam('myslug');
var subValues = Meteor.subscribe('SingleSchool', myslug );
if (myslug ) {
let Schools = SchoolDb.findOne({slug: myslug});
if (Schools && subValues.ready()) {
return Schools;
}
}
}
},
Publish file
Meteor.publish('SingleSchool', function (schoolSlug) {
check( schoolSlug, Match.OneOf( String, null, undefined ) );
user = Meteor.users.findOne({_id:this.userId})
if(user) {
if(user.emails[0].verified) {
return SchoolDb.findOne({ slug: schoolSlug, userId: {$lt: this.userId}});
} else {
throw new Meteor.Error('Not authorized');
return false;
}
}
});
template file
<template name="view">
{{#if currentUser}}
{{#if Template.subscriptionsReady }}
{{#with singleSchool}}
{{singleSchool._id}}
{{singleSchool.addschoolname}}
{{/with}}
{{/if}}
{{/if}}
</template>
As you said "This code snippet does not display anything on the view." well, inside Meteor.publish you need to return cursor, not array or any other object.
So use this code:
Meteor.publish('SingleSchool', function (schoolSlug) {
check( schoolSlug, Match.OneOf( String, null, undefined ) );
var user = Meteor.users.findOne({_id:this.userId});
if(!user || !user.emails[0].verified) {
throw new Meteor.Error('Not authorized');
}
return SchoolDb.find({ slug: schoolSlug, userId: {$lt: this.userId}},{limit:1});
});
I would definitely recommend you to go through How to avoid Common Mistakes
When I am concerned only for a single object, I implement this using a meteor method:
Meteor.methods({
"getSingleSchool":function(schoolSlug) {
//... check args and user permissions
return SchoolDb.findOne({ slug: schoolSlug, userId: {$lt: this.userId}});
},
});
Then in the template I run this method in the onCreated autorun part:
Template.view.onCreated(function(){
const instance = this;
instance.state = new ReactiveDict();
instance.autorun(function(){
let my slug = FlowRouter.getParam('myslug');
// load if no loaded yet
if (my slug && !instance.state.get("singleSchool")) {
Meteor.call("getSingleSchool", mySlug, function(err, res){
//handle err if occurred...
this.state.set("singleSchool", res);
}.bind(instance)); //make instance available
}
});
});
The helper then just returns a value, if the school is loaded:
singleSchool: function () {
return Template.instance().state.get("singleSchool");
},
I want to register a helper that i can use in the templates to check if a document exists.
I check if a document exists like this
var selector = {
userid: "3R2pKdT3x9PjWLsD8",
};;
var this_exists = Af.find(selector, {limit: 1}).count() > 0;
I am trying to register a helper like this
Template.registerHelper('ex', function() {
var selector = {
userid: "3R2pKdT3x9PjWLsD8",
};
var this_exists = Af.find(selector, {limit: 1}).count() > 0;
if(this_exists == true) {
return true;
} else {
return false;
}
});
and use it like this in my tempates
{{#if ex}}
{{> quickForm collection="Af" doc=cdoc id="updateSettings" omitFields="userid" class="settings" type="update" buttonContent="Update Settings"}}
{{else}}
{{> quickForm collection="Af" doc=this id="updateSettings" omitFields="userid" class="settings" type="insert" buttonContent="Insert Settings"}}
{{/if}}
but this does not work. Where am i going wrong?.
If this doesn't solve your problem, then there might a problem with your pub/sub.
You don't need limit. Instead use findOne and you don't need to check the count.
var exists = Af.findOne({userId: "3R2pKdT3x9PjWLsD8"}); //be careful with userId here, as it might be userid in your codes.
If(exists){
return true;
} //we don't need else block here. Your html if else block will work fine with this.
Additionally, if the userId you use is current user's id, you can use Meteor.userId()
var exists = Af.findOne({userId: Meteor.userId()});
why is this an endless loop? [ Iron Router + Fast Render + Blaze]
Router.route("/:cycle_uri", {
name: "cycle"
,template: "home"
,onBeforeAction: function () {
console.log("is there a loop here?") // this is what confirms that it's a continuous loop
var cycle = Cycles.findOne({
"uri": this.params.cycle_uri
});
if (typeof cycle === "undefined") {
this.render("notFound"); return;
} else {
ActiveCycle.set(cycle); // if I remove this, there is no continuous loop anymore... but if I remove it I don't see how to have this info in the client
this.render("home");
}
}
,waitOn: function () {
Meteor.subscribe('featuredListsPub', {
'program_id': this.params.cycle_uri
});
}
,fastRender: true
});
I was trying to update ActiveCycle variable so I can read it in the frontend but it's not actually working... I'm certainly doing something wrong, but would like to first understand why updating the reactive var is creating a loop.
I've also tried
if (ActiveCycle.get() !== cycle) {
ActiveCycle.set(cycle);
}
but it also enters a loop... which I don't understand why
for your question in the comments:
How do you subscribe to two publications:
here is my answer:
waitOn: function () {
return [
Meteor.subscribe('subscription1'), Meteor.subscribe('subscription2')
];
}
However, i strongly recommend:
Create on publication and return two cursors
Use Template level subscriptions
Good Luck!
An example of Template level subscriptions:
Template.templatename.onCreated(function () {
Template.autorun(function () {
var subscription = Meteor.subscribe('some_publication');
if (subscription.ready()) {
// do something
}
});
});
and within the template
<template name="templatename">
{{#if Template.subscriptionsReady}}
<div>Your Template here...</div>
{{else}}
<p>Loading...</p>
{{/if}}
</template>
A nice article is right here.
I need to know about to get array data of collections using Meteor JS. I did a simple example with insert data to collections in Meteor JS as shown below :
if (Hcare_Fileds.find().count() === 0) {
var fieldData = [
{fieldName: "Hcare1",
fieldOptions: [ "Bike","Car","TV","Radio","etc"]
},
{fieldName: "Hcare2",
fieldOptions: [ "Bike1","Car1","TV1","Radio1","etc"]
},
{fieldName: "Hcare3",
fieldOptions: [ "Bike2","Car2","TV2","Radio2","etc"]
}
];
for (var i = 0; i < fieldData.length; i++)
{
var list_id = Hcare_Fileds.insert({fieldname: fieldData[i].fieldName,fieldoptions: fieldData[i].fieldOptions}
, function( error, result)
{
if ( error ) console.log ( "Error :"+error.reason ); //info about what went wrong
if ( result )
{
console.log ( "Success="+result );//the _id of new object if successful
}
});
}
}
And Access the above collection fieldoption array data sa shown below :
{{#each fieldName}}
<div class="fmenu {{isselected}}"> {{ fieldname }} </div>
<div class="foptions">
{{#if isselected}}
{{ fieldoptions }}
// Here get fieldoptions data when selected filedname as Bike,Car,Tv,Radio,etc but i need to return like as array but it returns string
{{/if}}
</div>
{{/each}}
JS Code :
if (Meteor.isClient)
{
Session.set('currentFieldName', '');
Template.main.fieldName = function ()
{
return Hcare_Fileds.find().fetch();
};
//TODO ::
Template.main.events
({
'click .fmenu': function (e,t)
{
// template data, if any, is available in 'this'
if (typeof console !== 'undefined')
console.log("You pressed the button"+this.fieldname);
e.preventDefault();
Session.set('currentFieldName', this.fieldname);
}
});
Template.main.isselected = function ()
{
console.log("currentFieldName");
return Session.equals("currentFieldName", this.fieldname) ? "selected" : '';
};
}
I need to get data as array not string like Bike,Car,Tv,Radio,etc. I didn't get any idea about this.So Can you please suggest me what to do?