How to deal with checkboxes in meteor - meteor

Following from this question it appears I have to go around the houses with Meteor just to flag a checkbox as checked - but I've been Googling for an hour now and I can't find any examples of how to actually do it.
I've created the base of a helper:
Template.Settings.helpers({
isChecked: function () {
var id = this.id;
console.log(id);
}
});
And here's the HTML:
<input type="checkbox" name="imaname" id="imanid" {{isChecked}} />
However I'm clearly misunderstanding the context of this as literally whatever I try returns undefined (this.target etc. all nada). No docs I can find elaborate on how to actually create the isChecked helper that I'm supposed to use, so I'm now lost and frustrated.
Where do I go from here?
Edit: OK so I have it working, however I'd still like to know what the context of this is (maybe a duh moment, I guess the context is the helper itself… how do I access the element that triggers the helper?) - so I can make it a little more dynamic:
Template.Settings.helpers({
isChecked: function (value) {
return (value == 'on' ? 'checked' : false);
}
});
Along with:
<input type="checkbox" checked={{ isChecked currentUser.profile.services.bananaExports }} />

I'd still like to know what the context of this is
In a Blaze template helper this refers to the data context where the helper was called, which is the data context of the template unless you've set the context to be something else. To learn about data contexts see Discover Meteor's Guide on the topic.
how do I access the element that triggers the helper
Blaze doesn't have any way of telling you where in the DOM a helper was called, it only has access to the data context and any arguments you pass to the helper.
If you really have to access the DOM node you need to use Template.instance().find('some query') or Template.instance().$('some query') for a JQuery object.
An alternative way of marking a checkbox as checked is to define it like this
<input type="checkbox" name="imaname" id="imanid" checked={{isChecked}} />
And then setting isChecked to true or false in your helper.

If I understand your question, here's my approach, instead of using helper, you better use blaze template event handler and jquery like below:
Template.Setting.event({
'click input'(event){
if($('#imanid').is(":checked") == true){
return true;
}else{
return false;
}
}
});
hope this helps

Related

Meteor: Using If condition to conditionally display templates when user clicks a navigation link

I have some templates corresponding to different places. I am using a navigation bar which has links to different places(Manali). I want the corresponding template to be displayed when a particular link is being clicked. I tried assigning id to each anchor link and use it inside the #if loop of the main file. Like below.
{{#if equals id 'badrinath'}}
{{> Manali}}
{{/if}
I created a helper function also for the comparison purpose.
UI.registerHelper('equals', function(a, b) {
return a == b;
});
But it isn't working. Can anyone suggest a solution. What property of the link can I capture and use it to display the template accordingly.
You sound to be looking for "routing" functionality.
You might be interested in Iron Router or Flow Router.
You can still implement your functionality without router, as it sounds still a simple situation as described. You are probably just lacking some event listeners to set your id variable to the correct value.
Probably something like:
<a data-role="changetemplate" href="targetTemplate">To Target Template</a>
var id = new ReactiveVar(); // add the reactive-var package
Template.myTemplate.helpers({
id: function () {
return id.get();
}
});
Template.myTemplate.events({
"click a[data-role='changetemplate']": function (event) {
event.preventDefault();
id.set(event.currentTarget.href);
}
});

Translating number into currency without jQuery or manipulating the DOM

It is said that,
A good rule of thumb is that if you're using jQuery to manipulate any
DOM elements, you're probably doing it wrong.
And:
Needing access to an element from a helper function indicates that you
are trying to use a procedural coding style rather than a
template-driven style.
I have a simple number input that I wish to translate into a more comprehensible currency outside it so that the user understands what he is doing. I wanted to do this:
<input type="number" class="raw-price">
<p>Price in USD: {{priceInUsd}}</p>
And then define a helper:
Template.myTemplate.helpers({
priceInUsd: function() {
var rawPrice = $('.raw-price').val()
//perform calculation
return calculationResult
}
})
First of all, this isn't working (I don't really know why). Second, this goes against the "rules" I posted above. How am I supposed to do it? I probably could do this the same way using an event listener instead, but that would still be the wrong approach, I assume.
Flash update!
Actually! Here's a better solution: reactive variables! If you wish to keep your rawPrice in this one template, just install the standard reactive-var package:
meteor add reactive-var
And go at it this way:
Template:
<input type="number" class="raw-price">
<p>Price in USD: {{priceInUsd}}</p>
onCreated:
Template.myTemplate.onCreated(function() {
this.rawPrice = new ReactiveVar;
this.rawPrice.set(''); // not sure what you want to preset your value to
});
Helper:
Template.myTemplate.helpers({
priceInUsd: function() {
var rawPrice = Template.instance().rawPrice.get()
//perform calculation
return calculationResult
}
})
Event:
Template.myTemplate.events({
"change .raw_price": function (evt, template) {
template.rawPrice.set($(evt.currentTarget).val());
}
});
Previous (accepted) answer
According to most examples of two-way data binding in meteor I have seen, best case would probably be to use a helper, an event and a Session variable, like so.
Template:
<input type="number" class="raw-price">
<p>Price in USD: {{priceInUsd}}</p>
Helper:
Template.myTemplate.helpers({
priceInUsd: function() {
var rawPrice = Session.get('rawPrice');
//perform calculation
return calculationResult
}
})
Event:
Template.myTemplate.events({
"change .raw_price": function (evt) {
Session.set("rawPrice", $(evt.currentTarget).val());
}
});
Sadly, you're using a session variable, but it is still better than using a collection for such a local thing, like I saw in other examples...

Why are my <select>'s <option>'s not accessible from a Template.foo.rendered callback?

Here's my callback:
Template.joinedRoomsList.rendered = function () {
// the console.log prints: 'undefined' in client console
console.log($('#joined-rooms').children().first().html());
Session.set('currentRoom', $('#joined-rooms').children().first().text());
}
Here's my template:
<template name="joinedRoomsList">
<select id="joined-rooms">
{{#each joinedRooms}}
<option>{{name}}</option>
{{/each}}
</select>
</template>
I've tried many different ways to set the Session key 'currentRoom' to the value of the first in my .
The console.log statement prints out 'undefined', in the client console, however, when I manually type into the developer console the same thing: $('#joined-rooms').children().first().html(), it gives me a value.
Essentially, I'm trying to set the Session key 'currentRoom' to the first value in the on page load/body load/etc.
You can try to fix this by calling defer. I guess that you call your methods a bit too early - before the dom had time to render.
Template.joinedRoomsList.rendered = function () {
Meteor.defer(function(){
console.log($('#joined-rooms').children().first().html());
Session.set('currentRoom', $('#joined-rooms').children().first().text());
});
}
Try Template's selector, it's more efficient cause we just find elements inside our current Template instead of the whole doom with jQuery.
Template.joinedRoomsList.rendered = function() {
console.log(this.find("#joined-rooms"));
}

Meteorjs: value of this in helpers and events

I am new to Meteor so obviously I do not know the Meteor best practice. I am trying to understand the context this in a template's helpers and events functions. What I wanted was to tie the text of a div to an input field.
Coffeescript
Template.test.helpers
text: "initial text"
Template.test.events
"keypress #input": (e) ->
this.text = e.target.value
return
But I've learned that this does not point to test. What is the right way to access helpers from events?
Also I tried Tempalte.test.text = e.target.value though the value is changing, the DOM is not being updated. Aren't helpers supposed to be reactive?
You can't set helpers that way. If you want it to be reactive the best way is using a Session variable. I don't write coffescript but here's how you can do it with javascript:
Template.test.text = function(){
return Session.get("myTextVar");
};
Template.test.events({
"keypress #input":function(e,t){
Session.set("myTexVar",e.target.value);
}
});
You could also create your own reactive variables but that's too hard for that you need.

Trigger.io + Angular.js and updating a view after calling forge.ajax

Having a problem, and so far couldn't get any solutions for seemingly similar SO questions to work. Problem is this:
Using Trigger.io's forge.ajax, my Angular.js view is not updated after the data is returned. I realize this is because forge.ajax is an asychronous function, and the data is returned after the view has already been displayed. I have tried to update the view by using $rootScope.apply(), but it doesn't work for me as shown in the many examples I have seen.
See the Controller code below:
function OfferListCtrl($scope) {
$scope.offers = [];
$scope.fetchOffers = function(callback) {
$scope.offers = [];
var successCallback = function(odataResults) {
var rawJsonData = JSON.parse(odataResults);
var offers = rawJsonData.d;
callback(offers);
};
var errorCallback = function (error){
alert("Failure:" + error.message);
};
forge.request.ajax({
type: 'GET',
url: 'https://www.example.com/ApplicationData.svc/Offers',
accepts: 'application/json;odata=verbose',
username: 'username',
password: 'password',
success: successCallback,
error: errorCallback
});
};
$scope.fetchOffers(function(offers) {
$scope.offers = offers;
forge.logging.info($scope.offers);
});
}
All the code there works fine, and $scope.offers gets populated with the Offer data from the database. The logging function shows the data is correct, and in the correct format.
I have tried using $rootScope.apply() in the logical places (and some illogical ones), but cannot get the view to update. If you have any ideas how I can get this to work, I would greatly appreciate it.
Edit: Added HTML
The HTML is below. Note the button with ng-click="refresh()". This is a just a workaround so I can at least see the data. It calls a one-line refresh function that executes $rootScope.apply(), which does update the view.
<div ng-controller="OfferListCtrl">
<h1>Offers</h1>
<ul>
<li ng-repeat="offer in offers">
<p>Description: {{offer.Description}}<br />
Id: {{offer.Id}}<br />
Created On: {{offer.CreatedOn}}<br />
Published: {{offer.Published}}<br />
</p>
</li>
</ul>
<input type="button" ng-click="refresh()" value="Refresh to show data" />
</div>
You need to change
$scope.fetchOffers(function(offers) {
$scope.$apply(function(){
$scope.offers = offers;
});
forge.logging.info($scope.offers);
});
It is because all changes to the $scope has to be made within the angular scope, in this case since you are calling ajax request using forge the callback is not executing within the angular framework, that is why it is not working.
You can use $scope.$apply() in this case to execute the code within angular framework.
Look at the $apply() methods doc
$apply() is used to execute an expression in angular from outside of
the angular framework. (For example from browser DOM events,
setTimeout, XHR or third party libraries). Because we are calling into
the angular framework we need to perform proper scope life-cycle of
exception handling, executing watches.
do this
function MyController($scope, myService)
{
myService.fetchOffers(data){
//assign your data here something like below or whateever
$offers = data
$scope.$apply();
}
});
Thanks
Dhiraj
When I do that I have an error like : "$digest already in progress"...
I'm Working with $q...
Someone knwo how I can resolve this issue ?
yes, this is caused where ur data comes fast enough and angular has not finished his rendering so the update cant update "outside" angular yet.
so use events:
http://bresleveloper.blogspot.co.il/2013/08/angularjs-and-ajax-angular-is-not.html

Resources