How to access elements in the current template in meteor? - node.js

I have a template like this,
<template name = "foo">
<p id="loading" >LOADING...</p>
<p> {{theResult}} </p>
</template>
This is how I create foos,
// foos = [a, b, c, d]. With each button click I add a new item to the array
{{#each foos}}
{{> foo .}}
{{/each}}
And how a foo works,
Template.foo.created = function(){
var name = Template.currentData();
api_call(name, function(err, result){
Session.set(name, result);
});
}
Template.foo.helpers({
'theResult': function(){
var name = Template.currentData();
if(Session.get(name)) {
$("#loading").hide();
return Session.get(name);
} else {
return "";
}
}
})
So my expectation is to when the data came from the api_call, to hide "LOADING..." para, and to show the result in theResult.
The result is showing correctly. My problem is "LOADING..." is only get hidden on the top most foo. Not the other ones.
How can I fix this?
EDIT:
As suggested instead of,
$("#loading").hide();
I used,
Template.instance().$("#loading").hide();
This didn't work too :)

This is how I'd do it
Template... if theResult is undefined, the else path will be rendered.
<template name="foo">
{{#with theResult}}<p> {{this}} </p>
{{else}}<p id="loading" >LOADING...</p>
{{/with}}
</template>
Javascript... theResult is a simple Session.get call
Template.foo.helpers({
theResult: function(){
var name = Template.currentData();
return name && Session.get(name);
}
});

Thanks to Meteor templating engine, you can access a template scoped jQuery object that will only return elements within the corresponding template.
Template.foo.helpers({
'someText': function(){
var template = Template.instance();
template.$('p').changeSomeattr();
return Session.get('myPara');
}
});

Related

How to pass data from div like from input in nodejs

I want to pass data from quill editor but problem is that editor is div. In which is another div created after pageload.
Handlebars
<!-- Create the editor container -->
<div id="editor" name="body">
<div class="another div created after page load">
</div>
</div>
But problem is that i cant probably pass data from div it needs to be input but i have no idea how can i make it.
Controller for articles
exports.articleAdd = function (req, res) {
let article = new Article();
article.heading = req.body.heading;
article.author = req.user.firstname;
article.body = req.body.body;
article.save(function (err) {
if (err) {
console.log(err);
return;
} else {
res.redirect('/');
}
});
}
Its solved on their official site. https://quilljs.com/playground/#form-submit

How to return array of query results (Node.js & MongoDB)

I'm trying to create an array of query results so that I can use that array to populate one of my handlebars pages. Each index in the array holds Comments with a unique attribute. I currently have it set up like this:
This kicks the whole thing off:
//num is determined above
Comment.getComments(num, function(err, comments){
if(err){
console.log("ERROR");
}
console.log(comments);
res.render('page-i-want-to-populate-with-comments', {com : comments});
});
The getComments function calls this (in my models/comment.js):
module.exports.getComments = function(num, callback){
var comArr = [];
for(var i = 0; i < num; i++){
var uniqueId = i;
Comment.find({commentId : uniqueId}, function(err, items){
comArr.push(items);
});
}
callback(comArr);
}
Ideally I would then go to page-i-want-to-populate-with-comments.handlebars and:
{{#each com}}
<div class="comment-wrapper>
{{#each this}}
<div class="comment">
<p>{{this.text}}</p> //the text contained in the comment
</div>
{{/each}}
</div>
{{/each}}
My points of failure now are that comArr is empty when sent through callback() which causes an error in the callback function.
I get that this is probably confusing but this is the best I can explain it. I've been stuck on this for a while so any advice would be appreciated.

Rendering data in handlebars using express framework

Hello I am working in Express Framework, I am using handlebars to render the data from my mysql table. While trying to render the data using below code,instead of rendering value it displaying [object object]. I posted my code below.
index.js:
var query = connection.query('SELECT * FROM requestor_auth WHERE question_id = ? AND answer = ? AND app_key = ? LIMIT 1', [data.qid, data.ansvalue, data.appid], function(err,rows)
{
if(err) {
console.log("Error Selecting : %s ",err );
res.redirect('/');
} else {
res.render('requestform',{page_title:"Edit Customers - Node.js",data:rows});
}
requestform.hbs:
<div class="addressto">
<h4>To,</h4>
<br>
<span style="font-size:18px;margin-left:10px;">The Collector Of</span>
<input type="text" value="{{data}}" class="line" class="text-line" style="margin-left:35px;"><br>
</div>
The value in the form input displaying as [object object]. I tried as data.key_value to render the data but it is not displaying the value.
Please give me a solution. Thank you.
Because the result of Mysql response is array so it should be:
var query = connection.query('SELECT * FROM requestor_auth WHERE question_id = ? AND answer = ? AND app_key = ? LIMIT 1', [data.qid, data.ansvalue, data.appid], function(err,rows) {
if(err) {
console.log("Error Selecting : %s ",err );
res.redirect('/');
} else {
res.render('requestform',{page_title:"Edit Customers - Node.js",data:rows[0]});
}
If there's a same error you should console.log() your result to check the value.
The rows argument in your callback function is by a select query always an array of objects. With handlebars you should be able to do the following:
<div class="addressto">
<h4>To,</h4>
<br>
<span style="font-size:18px;margin-left:10px;">The Collector Of</span>
<input type="text" value="{{data[0].answer}}" class="line text-line" style="margin-left:35px;">
<br>
</div>
Also multiple class names can be in one class attribute.

Meteor - button click not updating value

I am trying to get a random document in the collection and display it on the page. It is successful every time I load the page, but I want a button to do the work as well.
main.html
<head>
<title>test</title>
</head>
<body>
<h1>Random Question</h1>
{{> question}}
</body>
<template name="question">
<button>Click Me</button>
{{#each object}}
{{question}}
{{a}}
{{b}}
{{c}}
{{d}}
{{answer}}
{{points}}
{{/each}}
</template>
main.js
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import './main.html';
Resolutions = new Mongo.Collection('quiz');
Template.question.created = function () {
var random = get_random();
this.question = new ReactiveDict();
this.question.set('object', random);
};
function get_random(){
var collection_size = Resolutions.find().count();
var random = Math.floor(Random.fraction() * collection_size);
// choose a random item by skipping N items
var item = Resolutions.findOne({},{
skip: random
});
var objArray = $.makeArray(item);
return objArray;
}
Template.question.helpers({
object: function () {
return get_random();
}
});
Template.question.events({
'click button': function (event, template) {
// increment the counter when button is clicked
var random = get_random();
template.question.set('object', random);
}
});
There is no error message when I load the page or click the button.
Any help is appreciated.
Btw, what is the object inside "this.question.set('object', random);". Maybe that's where my issue is.
You can considerably simplify your code and also solve your problem by not picking a random object in your helper - that will run many times, even when you don't expect it to. Also since you're only viewing a single object, use {{#with }} instead of {{#each }} - this will avoid the array conversion step.
html:
<template name="question">
<button>Click Me</button>
{{#with object}}
{{question}}
{{a}}
{{b}}
{{c}}
{{d}}
{{answer}}
{{points}}
{{/with}}
</template>
js:
import { Template } from 'meteor/templating';
import './main.html';
Resolutions = new Mongo.Collection('quiz');
Template.question.created = function () {
setRandom(); // initialize the random selection
};
function setRandom(){
var collection_size = Resolutions.find().count();
var random = Math.floor(Random.fraction() * collection_size);
Session.set('random',random);
}
Template.question.helpers({
object: function () {
return Resolutions.findOne({},{ skip: Session.get('random') });
}
});
Template.question.events({
'click button': function (event, template) {
setRandom();
}
});

AngularJS : How to say to a directive to clone scope?

I have this fiddle, and can not make this work. I believe that the reason resides in that two li elements with a custom directive edit-in-place share scope.
The solution would be to say to the directive to create a copy of the scope that binds on the parent - can transclude help?
angular.module('bla', [])
.directive('editInPlace', ['$parse','$compile', function($parse, $compile) {
return {
restrict: 'A',
scope: true,
link: function (scope, element, attribs) {
var inputStart = '<input style="border: 2 solid black" name="inPlaceInput" style="display:none" value="';
var inputEnd = '">';
scope.editModeAccessor = $parse(attribs.editInPlace);
scope.modelAccessor = $parse(attribs.ngBind);
scope.$watch(attribs.editInPlace, function(newValue, oldValue){
if (newValue){
console.debug("click");
console.debug("value: " + scope.modelAccessor(scope));
var inputHtml = inputStart + scope.modelAccessor(scope) + inputEnd;
element.after(inputHtml);
jQuery(element).hide();
scope.inputElement = jQuery("input[name=inPlaceInput]");
scope.inputElement.show();
scope.inputElement.focus();
scope.inputElement.bind("blur", function() {
blur();
});
} else {
blur();
}
});
function blur(){
console.debug("blur secondary");
if (scope.inputElement){
console.debug("blur secondary inputElement found");
var value = scope.inputElement.val();
console.debug("input value: "+ value);
scope.inputElement.remove();
jQuery(element).show();
scope.editModeAccessor.assign(scope, false);
scope.modelAccessor.assign(scope, value);
}
}
}
}
}]);
function ContactsCtrl($scope, $timeout){
$scope.contacts = [{number:'+25480989333', name:'sharon'},{number:'+42079872232', name:''}];
$scope.editMode = false;
var editedId;
$scope.edit = function(id){
$scope.editMode = true;
jQuery("#"+id).hide();
editedId = id;
//TODO show delete button
}
$scope.$watch('editMode', function(newValue, oldValue){
if (!newValue && editedId){
jQuery("#"+editedId).show();
}
});
}
<div ng-app="bla">
<div ng-controller="ContactsCtrl">
<h4>Contacts</h4>
<ul>
<li ng-repeat="contact in contacts">
<span edit-in-place="editMode" ng-bind="contact.number"></span>
<span edit-in-place="editMode" ng-bind="contact.name"></span>
<span id="{{$index}}" ng-click="edit($index)"><i class="icon-edit">CLICKtoEDIT</i></span>
</li>
</ul>
</div></div>
I think cloning the scope is not the best solution.
When creating a directive in angular, you should encapsulate all the functionality within the directive. You should also avoid mixing jQuery in when you don't have to. Most of the time (as in this case) you're just introducing unnecessary complexity. Lastly, classes are the best way of controlling display, rather than the style attribute on an element.
I took the liberty of rewriting your directive in a more "angular" way - with no jQuery. As you can see from the updated jsFiddle, it is simpler and cleaner. Also, it works!
This directive can be easily modified to add lots of additional awesome functionality.
app.directive( 'editInPlace', function() {
return {
restrict: 'E',
scope: { value: '=' },
template: '<span ng-click="edit()" ng-bind="value"></span><input ng-model="value"></input>',
link: function ( $scope, element, attrs ) {
// Let's get a reference to the input element, as we'll want to reference it.
var inputElement = angular.element( element.children()[1] );
// This directive should have a set class so we can style it.
element.addClass( 'edit-in-place' );
// Initially, we're not editing.
$scope.editing = false;
// ng-click handler to activate edit-in-place
$scope.edit = function () {
$scope.editing = true;
// We control display through a class on the directive itself. See the CSS.
element.addClass( 'active' );
// And we must focus the element.
// `angular.element()` provides a chainable array, like jQuery so to access a native DOM function,
// we have to reference the first element in the array.
inputElement[0].focus();
};
// When we leave the input, we're done editing.
inputElement.prop( 'onblur', function() {
$scope.editing = false;
element.removeClass( 'active' );
});
}
};
});

Resources