Passing the being looped element to event handler - node.js

How do I pass the element that is being loop to event handler.
foo.hbs
<div>
{{#each products}}
// some html code
<p>{{this}}</p> <!-- output product object -->
<button onclick="foo(this)">Add</button> <!-- output button object-->
<button onclick="foo({{this._id}})">Add</button> <!-- uncaught syntax error -->
{{/each}}
</div>
<script type="text/javascript">
function foo(product) {
console.log(product);
}
</script>
The above code: product argument gives me the HTMLButton instead of product of current iteration.
Question: How do I pass product instead of button element to the handler?
I'm using express-handlerbars.

You can try :
this.parentNode
which refers to html parent.
and in your function:
console.log(product.id);
console.log(typeof(product)); //display object
Console print html, but product is object you sent from onclick. So you can access to any related properties.
Hope it can help.

Related

How to use variables in _hyperscript js

I'm having fun with _hyperscript js which I find very promising and amusing.
Now I'm trying to understand the use of variables inside simple commands. Suppose that I have the following code generated by a PHP script that queried a dB and where ids are obtained the dB (a very common case):
<div id="1000">Mercedes</div>
<div id="1022">Audi</div>
<div id="1301">Ferrari</div>
<div id="1106">Lamborghini</div>
To add a class to a specific id I would normally do like this:
<button _="on click add .green to #1022" type="button">
Click
</button>
But what if I don't know the id because it's the result of a dB query? How can I place a variable using _hyperscript and set it with javascript? Something like this:
<button _="on click call setID() then add .green to ???" type="button">
Click
</button>
<script type="text/javascript">
function setID() {
// here the code to get the ID
return id;
}
</script>
Using the 'symbol' it to read the result of the last call returns error:
_="on click call setID() then add .green to it"
returns
Uncaught TypeError: target.classList is undefined
You can use string templates inside query literals, so something like this should work:
<button _="on click add .green to <#${getIdToAddTo()}/>" type="button">
Click
</button>
where the <.../> is the query literal and the ${getIdToAddTo()} is a string template within that query
Another alternative would be to create a method that returns the div to add to:
<script>
function divToAddTo() {
return document.getElementById("whatever");
}
</script>
<button _="on click add .green to divToAddTo()" type="button">
Click
</button>

If element hasClass, add another class to its title value

I'm using slick carousel, and once a div is active I want to open the corresponding description.
Problem I'm having is with this code:
if ($('div').hasClass('active')) {
var title = $(this).attr('title');
$('ul li').removeClass('open');
$(title).addClass('open');
}
What I'm trying to achieve:
Once a div gets class 'active', I want to take its title value, and use it as a id link to list element I want to display(add class to).
Here is a FIDDLE.
Use event handling, not class monitoring.
The slick carousel API has events for this, I believe you want to use the afterChange event to act on the active element after it has been made visible.
Check out the docs and examples, especially the section titled "Events" on Slick page: http://kenwheeler.github.io/slick/
And I think you don't want to use title attribute for this because that is for tooltips. I recommend data-* attributes instead. And element IDs should generally start with a letter and not a number (was required in HTML4 and makes life easier when mapping IDs to JavaScript variables; though if you are using HTML5 I think this requirement is no longer in effect).
HTML
<div id="carousel">
<div data-content-id="content1">
Selector 1 </div>
<div data-content-id="content2">
Selector 2 </div>
<div data-content-id="content3">
Selector 3 </div>
</div>
<ul class="content">
<li id="content1">Content 1</li>
<li id="content2">Content 2</li>
<li id="content3">Content 3</li>
</ul>
JavaScript
$('#carousel').on('afterChange', function(event, slick, currentSlide) {
// get the associated content id
var contentId = $(slick.$slides.get(currentSlide)).data("content-id");
if(contentId && contentId.length)
{
var $content = $("#" + contentId);
$(".content>li").removeClass("open"); // hide other content
$content.addClass("open"); // show target content, or whatever...
}
});
I have found a solution:
$('.slider').on('afterChange', function(event, slick, currentSlide, nextSlide){
var contentId= $(slick.$slides.get(currentSlide)).data('content');
if(contentId)
{
$(".content li").removeClass('open');
$('#' + contentId).addClass('open');
}
});
Working fiddle

App script doesn't update the google spreadsheet cell values always

I am using html code to create a dashboard where user can select a date and then based on selected date fetch some values from remote APIs and then show these values in the sheet.
I have html file something like:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<link rel="stylesheet" href="/resources/demos/style.css">
<script>
$(function() {
$( "#datepicker" ).datepicker();
});
</script>
</head>
<body>
<form>
<select name="Student" id="category">
<option value="" selected="selected">Select Student</option>
<option value="Abercrombie, Amber">Abercrombie, Amber(Gr 11)</option>
<option value="Yupa, Jason">Yupa, Jason(Gr 9)</option>
</select>
Date: <input type="text" id="datepicker" name="datepicker">
<input type="submit" value="Submit" onclick="myFunction()">
</form>
<p id="demo"></p>
<script>
function myFunction() {
var x = document.getElementById("category").value;
var x2 = document.getElementById("datepicker").value;
//document.getElementById("demo").innerHTML = x;
google.script.run.functionToRunOnFormSubmit(x, x2);
google.script.host.close();
}
</script>
</body>
</html>
I have code.gs as follows:
function fncOpenMyDialog() {
//Open a dialog
var htmlDlg = HtmlService.createHtmlOutputFromFile('HTML_myHtml')
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setWidth(500)
.setHeight(300);
SpreadsheetApp.getUi()
.showModalDialog(htmlDlg, 'Dashboard');
};
function functionToRunOnFormSubmit(fromInputForm, datevalue) {
Logger.log(fromInputForm);
Logger.log(datevalue);
SpreadsheetApp.getActiveSheet().getRange('B3').setValue(fromInputForm);
SpreadsheetApp.getActiveSheet().getRange('B4').setValue(datevalue);
};
When I select the function(fncOpenMyDialog()) from script-editor, It create a dashboard on the spreadsheet, Where I am able to select the date but as in functionToRunOnFormSubmit function I am logging the argument and then correspondingly setting the B3 and B4 cell values. It is not getting updated also It is not getting logged in the script editor.
The problem is you are calling "close" right after calling the google.script.run function which is an asynchronous ajax call.
In some cases it likely doesnt even give the browser enough time to start the ajax call or it gets cancelled because the page is closing. So sometimes it might reach the backend script, and sometimes wont.
take a look at the documentation and handle both success (close dialog from there) and failure (show error to the user)
https://developers.google.com/apps-script/guides/html/reference/run
While the documentation doesnt show it explicitly, you can hook both calls like this:
google.script.run.withFailureHandler(onFailure).withSuccessHandler(onSuccess).yourCall();

$scope.$apply and ng-include

I'm using a $scope.$apply to trigger the view to update based on a changed variable in the scope. However, I have another line in the html that is an ng-include,
<div data-ng-include data-ng-src="'views/partials/_menubar.html'"></div>
error message
When I remove the ng-include and replace it with a static call there is no error. Here is the template that I'm including as well:
<div class="menu" ng-controller="MenuController">
<div style="display: inline-block">
Hello!
</div>
<ul class="menu_dropdown">
<li class="menu_item">Test1</li>
<li class="menu_item">Test2</li>
<li class="menu_item">Test3</li>
</ul>
</div>
The code for menu controller is
app.controller('MenuController', function($scope) {
});
ng-src is used to allow elements that usually have a src (like anchors or images) to apply the src tag only after angular's digest, not for inclusion of templates in ng-include. See ng-include docs and ng-src docs.
A safe way to specify the src using ng-include would be like this:
<div data-ng-include="src='views/partials/_menubar.html'"></div>
or
<div data-ng-include="'views/partials/_menubar.html'"></div>
If you must have the src separately, it's data-src and not data-ng-src:
<div data-ng-include data-src="'views/partials/_menubar.html'"></div>
see plnkr.
edit: To address your error message.. you'll see that message if you've bound a function to the scope which changes every time it is called.
For example, this will cause such an error:
// controller
$scope.getQuote = function(){
return 'someViewName' + Math.ceil(Math.random() * 10) + '.html';
};
// view
<div data-ng-include="{{getQuote}}"></div>
The problem with ng-include was actually a red herring. The real problem was trying to change the window.history, as seen in the thread here. My guess is because the ng-include directive references $location when it attempts to get resources.

Rendering new div created dynamically with Meteor

I have a the classic "Thread->Posts" model.
In the application, I have a left sidebar with the "Thread" collections. When the user click in a Thread, I want to create another div with the Thread->Posts elements.
Is there any way to do this, conservating the reactivity?
For now, I've got this:
// In the client
Template.threadlist.events({
'click tr': function(event){
Session.set("selectedThread",this);
$("#posts").html( Meteor.render(Template["datathread"]) );
}
})
[...]
Template.datathread.events({
'click input.add-post' : function(event){
var t = Session.get("selectedThread");
Meteor.call("addPost", {"thread":t,"text":"foo","user":"var"},callback})
}
})
[...]
// In the server
addPost: function(param){
var id = Threads.update(param.thread,{ $addToSet: {"posts": {"text":param.text, "user": param.user}}});
return id;
}
The template with the posts is something like this:
<template name="datathread">
{{#each thread.posts}}
{{user}} says: {{text}}
<br />
{{/each}}
</template>
(The "user" and "text" propertis are from the "thread.posts" elements)
With this code, I only get the new values refreshing (F5) the webpage (or executing the 'click tr'event). What I'm doing wrong?
Thank you!
== Edit ==
Ok... Now, with the recomendation of Chistian Fritz, my code its something like this:
// In the client
Template.datathread.thread = function(){
return Session.get("selectedThread");
}
[...]
Template.threadlist.events({
'click tr': function(event){
Session.set("selectedThread",this);
}
});
//In the html
<div class="span5" id="threads">
{{> datathread}}
</div>
<template name="datathread">
{{#if thread}}
<hr />
{{#each thread.posts}}
{{user}} says: {{text}}
<br />
{{/each}}
{{/if}}
</template>
The changes are great (it's so simple!), but the reactivity still doesn't work :(....
The problem is that you are using jQuery to fill your DOM:
$("#posts").html( Meteor.render(Template["datathread"]) );
This breaks the reactivity chain.
You are only showing part of your code, so I can't give you the full solution, but it seems that the datathread template is already using the selectedThread session variable -- which is good. Hence, it might be as easy as using {{> datathread}} in place of the #posts element in your HTML.
EDIT:
One thing that you need to change is the scope you are assuming datathread: it's already the thread itself, if I understand correctly:
<template name="datathread">
<hr />
{{#each posts}}
{{user}} says: {{text}}
<br />
{{/each}}
</template>
Also, the this in the threadlist event handler most certainly won't be the thread. I don't know the data of the tr in the threadlist (can you show that code?), but you will most probably do something like the following:
Session.set("selectedThread", this.id);
And for datathread:
Template.datathread.thread = function(){
return Threads.find({_id: Session.get("selectedThread")});
}
or similar.

Resources