JavaScript
$.each(['#clk','#clk1'], function()
{
$(this).click(function () {
alert("click")
});
});
HTML
click me
click me
No alert box when the link is clicked.
UPDATE:
I have more than 1 id. I have shown only one to simplify the problem.
You will have to use String.toString() to get the value of the String object.
It´s not clear why you would need an array of selectors but here are two solutions;
Your solution using String.toString();
// Array of strings to be used as element selectors.
var selectors = ['#element1', '#element2'];
// Using $.each()
$.each(selectors, function() {
// String.toString() returns the value of the String object.
var $this = $(this.toString());
$this.click(function () {
console.log('Clicked element(1) =', this.id || this); // DEBUG
});
});
Alternative solution using String.join();
// Using String.join()
$(selectors.join(',')).click(function(event) {
event.preventDefault(); // This is to not follow the link
// Notice that "this" now referes to the current/clicked element
// and not any string value from the "selectors" array.
console.log('Clicked element(2) =', this.id || this); // DEBUG
});
See my demo.
If you don´t really need the array of selectors I would recommend a simple multiple selector like this;
$('#element1, #element2').click(function() { ... });
You could further simplify it to:
$("#clk").click (function () {
alert("click");
});
Firstly, why are you using a foreach construct when iterating over an id? When you are using and id, there is supposed to be EXACTLY ONE element with the given id. So, this should be fine:
$("#clk").click(function() {
alert("click");
});
Secondly, each iterates over an array, your array being #clk. Just the string, nothing else. All your function gets is two parameters: 0' (the index of the element) and the string#clk` (the value at that index). The string IS NOT resolved to a JS object.
IMO, the cleanest way to solve your problem statement would be:
$("a[id^='clk']").click(function () {
alert("click");
});
The ^= selector would select all anchors whose id starts with 'clk' and bind the click function to all of those. You can read more about this selector here
Related
I've read in several places that the key difference is that this is lexically bound in arrow functions. That's all well and good, but I don't actually know what that means.
I know it means it's unique within the confines of the braces defining the function's body, but I couldn't actually tell you the output of the following code, because I have no idea what this is referring to, unless it's referring to the fat arrow function itself....which doesn't seem useful.
var testFunction = () => {
console.log(this)
};
testFunction();
Arrow functions capture the this value of the enclosing context
function Person(){
this.age = 0;
setInterval(() => {
this.age++; // |this| properly refers to the person object
}, 1000);
}
var p = new Person();
So, to directly answer your question, this inside your arrow function would have the same value as it did right before the arrow function was assigned.
In order to provide the big picture I'm going to explain both, dynamic and lexical binding.
Dynamic Name Binding
this refers to the object the method is called on. This is a regularly to be read sentence on SO. But it is still only a phrase, pretty abstract. Is there a corresponding code pattern to this sentence?
Yes there is:
const o = {
m() { console.log(this) }
}
// the important patterns: applying methods
o.m(); // logs o
o["m"](); // logs o
m is a method because it relies on this. o.m() or o["m"]() means m is applied to o. These patterns are the Javascript translation to our famous phrase.
There is another important code pattern that you should pay attention to:
"use strict";
const o = {
m() { console.log(this) }
}
// m is passed to f as a callback
function f(m) { m() }
// another important pattern: passing methods
f(o.m); // logs undefined
f(o["m"]); // logs undefined
It is very similar to the previous pattern, only the parenthesis are missing. But the consequences are considerable: When you pass m to the function f, you pull outm of its object/context o. It is uprooted now and this refers to nothing (strict mode assumed).
Lexical (or Static) Name Binding
Arrow functions don't have their own this/super/arguments binding. They inherit them from their parent lexical scope:
const toString = Object.prototype.toString;
const o = {
foo: () => console.log("window", toString.call(this)),
bar() {
const baz = () => console.log("o", toString.call(this));
baz();
}
}
o.foo() // logs window [object Window]
o.bar() // logs o [object Object]
Apart from the global scope (Window in browsers) only functions are able to form a scope in Javascript (and {} blocks in ES2015). When the o.foo arrow function is called there is no surrounding function from which baz could inherit its this. Consequently it captures the this binding of the global scope which is bound to the Window object.
When baz is invoked by o.bar, the arrow function is surrounded by o.bar (o.bar forms its parent lexical scope) and can inherit o.bar's this binding. o.bar was called on o and thus its this is bound to o.
Hope this code show could give you clearer idea. Basically, 'this' in arrow function is the current context version of 'this'. See the code:
// 'this' in normal function & arrow function
var this1 = {
number: 123,
logFunction: function () { console.log(this); },
logArrow: () => console.log(this)
};
this1.logFunction(); // Object { number: 123}
this1.logArrow(); // Window
Arrow function this is pointing to the surrounding parent in Es6, means it doesn't scope like anonymous functions in ES5...
It's very useful way to avoid assigning var self to this which is widely used in ES5...
Look at the example below, assigning a function inside an object:
var checkThis = {
normalFunction: function () { console.log(this); },
arrowFunction: () => console.log(this)
};
checkThis.normalFunction(); //Object {}
checkThis.arrowFunction(); //Window {external: Object, chrome: Object, document: document, tmpDebug: "", j: 0…}
You can try to understand it by following the way below
// whatever here it is, function or fat arrow or literally object declare
// in short, a pair of curly braces should be appeared here, eg:
function f() {
// the 'this' here is the 'this' in fat arrow function below, they are
// bind together right here
// if 'this' is meaningful here, eg. this === awesomeObject is true
console.log(this) // [object awesomeObject]
let a = (...param) => {
// 'this is meaningful here too.
console.log(this) // [object awesomeObject]
}
so 'this' in fat arrow function is not bound, means you can not make anything bind to 'this' here, .apply won't, .call won't, .bind won't. 'this' in fat arrow function is bound when you write down the code text in your text editor. 'this' in fat arrow function is literally meaningful here. What your code write here in text editor is what your app run there in repl. What 'this' bound in fat arror will never change unless you change it in text editor.
Sorry for my pool English...
Arrow function never binds with this keyword
var env = "globalOutside";
var checkThis = {env: "insideNewObject", arrowFunc: () => {
console.log("environment: ", this.env);
} }
checkThis.arrowFunc() // expected answer is environment: globalOutside
// Now General function
var env = "globalOutside";
var checkThis = {env: "insideNewObject", generalFunc: function() {
console.log("environment: ", this.env);
} }
checkThis.generalFunc() // expected answer is enviroment: insideNewObject
// Hence proving that arrow function never binds with 'this'
this will always refer to the global object when used inside an arrow function. Use the regular function declaration to refer to the local object. Also, you can use the object name as the context (object.method, not this.method) for it to refer to the local object instead of the global(window).
In another example, if you click the age button below
<script>
var person = {
firstName: 'John',
surname: 'Jones',
dob: new Date('1990-01-01'),
isMarried: false,
age: function() {
return new Date().getFullYear() - this.dob.getFullYear();
}
};
var person2 = {
firstName: 'John',
surname: 'Jones',
dob: new Date('1990-01-01'),
isMarried: false,
age: () => {
return new Date().getFullYear() - this.dob.getFullYear();
}
};
</script>
<input type=button onClick="alert(person2.age());" value="Age">
it will throw an exception like this
×JavaScript error: Uncaught TypeError: Cannot read property
'getFullYear' of undefined on line 18
But if you change person2's this line
return new Date().getFullYear() - this.dob.getFullYear();
to
return new Date().getFullYear() - person2.dob.getFullYear();
it will work because this scope has changed in person2
Differences between arrow functions to regular functions: (taken from w3schools)
With arrow functions there are no binding of this.
In regular functions the this keyword represented the object that called the function, which could be the window, the document, a button or whatever.
With arrow functions the this keyword always represents the object that defined the arrow function.
// Regular Function:
hello = function() {
document.getElementById("demo").innerHTML += this;
}
// The window object calls the function:
window.addEventListener("load", hello);
// A button object calls the function:
document.getElementById("btn").addEventListener("click", hello);
// -------------------------------------------
// Arrow function
hello2 = () => {
document.getElementById("demo2").innerHTML += this;
}
// The window object calls the function:
window.addEventListener("load", hello2);
// A button object calls the function:
document.getElementById("btn2").addEventListener("click", hello2);
<p><i>With a regular function this represents the <b>object that calls the function</b>:</i></p>
<button id='btn'>click me regular function</button>
<p id="demo">Regular function: </p>
<hr>
<p><i>With arrow function this represents the <b>owner of the function(=the window object)</b>:</i></p>
<button id='btn2'>click me arrow function</button>
<p id="demo2">Arrow function: </p>
A related issue:
Came from - Why can't I access `this` within an arrow function?
We know below from here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Does not have its own bindings to this or super, and should not be used as methods.
Arrow functions establish "this" based on the scope the Arrow function is defined within.
Had a issue with this using arrow functions, so created a class (can be function), and class variable is accessed in arrow function, thereby achieved smaller functions using arrow functions without function keyword:
class MyClassOrFunction {
values = [];
size = () => this.values.length;
isEmpty = () => this.size() === 0;
}
let obj = new MyClassOrFunction();
obj.size(); // function call here
You can also have a getter like this, that does not have function keyword, but a bit longer due to return statement, also can access other member functions:
class MyClassOrFunction {
values = [];
size = () => this.values.length;
get length() { return this.size(); }
}
let obj = new MyClassOrFunction();
obj.length; // NOTE: no function call here
i have problem rendering my view...the view return always the last in the json object: This is the code:
Router.js:
var list = new clientCollection();
var cards = new cardsView({model:list})
list.fetch({success: function (collection, response, options) {
cards.render();
}
});
Cards.js view:
....
tagName: 'section',
className: 'list',
template: Handlebars.compile(cardsTemplate),
render: function () {
var list = this.model.toJSON(),
self = this,
wrapperHtml = $("#board"),
fragment = document.createDocumentFragment();
$(list).each(function (index, item) {
$(self.el).html(self.template({card: item}));
$.each(item.cards, function (i, c) {
var card = new cardView({model : c});
$(self.el).find('.list-cards').append(card.render().el);
});
fragment.appendChild(self.el);
});
wrapperHtml.append(fragment.cloneNode(true));
},
...
This is my json data:
[
{"id":"9","name_client":"XXXXXXX","cards":[]},
{"id":"8","name_client":"XXXXXXX","cards":[{"id":"8","title":"xxxxx.it","description":"some desc","due_date":"2016-01-23","sort":"0"}]}
]
Can u help me to render the view?
It's hard to know for sure without seeing how the view(s) are attached to the DOM, but your problem appears to be this line ...
$(self.el).html(self.template({card: item}));
That is essentially rendering each element in the collection as the full contents of this view, then replacing it on each iteration. Try instead appending the contents of each template to the view's element.
Also, since you tagged this with backbone.js and collections, note that the easier, more Backbone-y way to iterate through a collection would be:
this.model.each(function(item) {
// 'item' is now an instance of the Backbone.Model type
// contained within the collection. Also, note the use
// of 'this' within the iterator function, as well as
// this.$el within a View is automatically the same as
// $(self.el)
this.$el.append(this.template({ card: item });
// ... and so on ...
// By providing 'this' as the second argument to 'each(...)',
// the context of the iterator function is set for you.
}, this);
There's a lot packed in there, so ...
Backbone.Collection Underscore Methods
Backbone.View this.$el
I have a Polymer element of which the public API should allow to bind to a function which the user can define, i.e. it should allow to pass in a function implementation. I have tried quite a few approaches but only 1 worked. Now I'm wondering if this is the proper / correct way or not.
To rephrase: what is the proper way to bind a function as part of a dom-module's public API? The only way I have this achieved somewhat is as follows:
<dom-module id="channel-search">
<template>
<remote-dropdown
id="dropdown"
label-text="Type channel name"
url='{{_findRecordUrl}}'
url-transformer='{{urlTransformer}}'
result-to-list-transformer='{{resultToListTransformer}}'
class="layout horizontal"
style='width: 100%'>
</remote-dropdown>
</template>
</dom-module>
<script>
(function() {
Polymer({
is: 'channel-search',
properties: {
_findRecordUrl: {
type: String,
value: 'http://127.0.0.1:9292/epics-boot-info.psi.ch/find-channel.aspx'
}
},
/*
* Here in the attached function, I define the methods which will then be bound to
* the respective properties of the remote-dropdown element
*/
attached: function() {
this.urlTransformer = function(baseUrl, currentInput) {
return baseUrl + '/' + currentInput;
};
this.resultToListTransformer = function(findRecordList) {
var responseList = findRecordList.map(function(res) {
return res.Channel;
});
return responseList;
};
}
});
})();
</script>
So, I needed to define the functions in the attached callback in order for them to be properly bound to the remote-dropdown element's public API.
I hoped it would be a bit clearer / easier, maybe like so:
<script>
(function() {
Polymer({
is: 'channel-search',
properties: {
_findRecordUrl: {
type: String,
value: 'http://127.0.0.1:9292/find-channel.aspx'
}
},
urlTransformer: function(baseUrl, currentInput) {
return baseUrl + '/' + currentInput;
};
resultToListTransformer: function(findRecordList) {
var responseList = findRecordList.map(function(res) {
return res.Channel;
});
return responseList;
};
});
})();
</script>
i.e. simply define the function implementation as part of the element's definition and then bind those to the embedded remote-dropdown element. However, that never seemed to work as I thought it would (also not variations thereof) - surely also because of my limited knowledge of Polymer/Javascript internals.
My question is: is the solution using the attached callback the proper way to achieve what I am trying to do? If not, what would be the correct way to implement this?
You can probably do that using computed properties or computed bindings. Your first answer looks like a variation of the latter.
I want to create a directive that links to an attribute. The attribute specifies the function that should be called on the scope. But I also want to pass an argument to the function that is determined inside the link function.
<div my-method='theMethodToBeCalled'></div>
In the link function I bind to a jQuery event, which passes an argument I need to pass to the function:
app.directive("myMethod",function($parse) {
restrict:'A',
link:function(scope,element,attrs) {
var expressionHandler = $parse(attrs.myMethod);
$(element).on('theEvent',function( e, rowid ) {
id = // some function called to determine id based on rowid
scope.$apply(function() {expressionHandler(id);});
}
}
}
app.controller("myController",function($scope) {
$scope.theMethodToBeCalled = function(id) { alert(id); };
}
Without passing the id I can get it working, but as soon as I try to pass an argument, the function is not called anymore
Marko's solution works well.
To contrast with recommended Angular way (as shown by treeface's plunkr) is to use a callback expression which does not require defining the expressionHandler. In marko's example change:
In template
<div my-method="theMethodToBeCalled(myParam)"></div>
In directive link function
$(element).click(function( e, rowid ) {
scope.method({myParam: id});
});
This does have one disadvantage compared to marko's solution - on first load theMethodToBeCalled function will be invoked with myParam === undefined.
A working exampe can be found at #treeface Plunker
Just to add some info to the other answers - using & is a good way if you need an isolated scope.
The main downside of marko's solution is that it forces you to create an isolated scope on an element, but you can only have one of those on an element (otherwise you'll run into an angular error: Multiple directives [directive1, directive2] asking for isolated scope)
This means you :
can't use it on an element hat has an isolated scope itself
can't use two directives with this solution on the same element
Since the original question uses a directive with restrict:'A' both situations might arise quite often in bigger applications, and using an isolated scope here is not a good practice and also unnecessary. In fact rekna had a good intuition in this case, and almost had it working, the only thing he was doing wrong was calling the $parsed function wrong (see what it returns here: https://docs.angularjs.org/api/ng/service/$parse ).
TL;DR; Fixed question code
<div my-method='theMethodToBeCalled(id)'></div>
and the code
app.directive("myMethod",function($parse) {
restrict:'A',
link:function(scope,element,attrs) {
// here you can parse any attribute (so this could as well be,
// myDirectiveCallback or multiple ones if you need them )
var expressionHandler = $parse(attrs.myMethod);
$(element).on('theEvent',function( e, rowid ) {
calculatedId = // some function called to determine id based on rowid
// HERE: call the parsed function correctly (with scope AND params object)
expressionHandler(scope, {id:calculatedId});
}
}
}
app.controller("myController",function($scope) {
$scope.theMethodToBeCalled = function(id) { alert(id); };
}
Not knowing exactly what you want to do... but still here's a possible solution.
Create a scope with a '&'-property in the local scope.
It "provides a way to execute an expression in the context of the parent scope" (see the directive documentation for details).
I also noticed that you used a shorthand linking function and shoved in object attributes in there. You can't do that. It is more clear (imho) to just return the directive-definition object. See my code below.
Here's a code sample and a fiddle.
<div ng-app="myApp">
<div ng-controller="myController">
<div my-method='theMethodToBeCalled'>Click me</div>
</div>
</div>
<script>
var app = angular.module('myApp',[]);
app.directive("myMethod",function($parse) {
var directiveDefinitionObject = {
restrict: 'A',
scope: { method:'&myMethod' },
link: function(scope,element,attrs) {
var expressionHandler = scope.method();
var id = "123";
$(element).click(function( e, rowid ) {
expressionHandler(id);
});
}
};
return directiveDefinitionObject;
});
app.controller("myController",function($scope) {
$scope.theMethodToBeCalled = function(id) {
alert(id);
};
});
</script>
You can create a directive that executes a function call with params by using the attrName: "&" to reference the expression in the outer scope.
We want to replace the ng-click directive with ng-click-x:
<button ng-click-x="add(a,b)">Add</button>
If we had this scope:
$scope.a = 2;
$scope.b = 2;
$scope.add = function (a, b) {
$scope.result = parseFloat(a) + parseFloat(b);
}
We could write our directive like so:
angular.module("ng-click-x", [])
.directive('ngClickX', [function () {
return {
scope: {
// Reference the outer scope
fn: "&ngClickX",
},
restrict: "A",
link: function(scope, elem) {
function callFn () {
scope.$apply(scope.fn());
}
elem[0].addEventListener('click', callFn);
}
};
}]);
Here is a live demo:
http://plnkr.co/edit/4QOGLD?p=info
Here's what worked for me.
Html using the directive
<tr orderitemdirective remove="vm.removeOrderItem(orderItem)" order-item="orderitem"></tr>
Html of the directive: orderitem.directive.html
<md-button type="submit" ng-click="remove({orderItem:orderItem})">
(...)
</md-button>
Directive's scope:
scope: {
orderItem: '=',
remove: "&",
My solution:
on polymer raise an event (eg. complete)
define a directive linking the event to control function
Directive
/*global define */
define(['angular', './my-module'], function(angular, directives) {
'use strict';
directives.directive('polimerBinding', ['$compile', function($compile) {
return {
restrict: 'A',
scope: {
method:'&polimerBinding'
},
link : function(scope, element, attrs) {
var el = element[0];
var expressionHandler = scope.method();
var siemEvent = attrs['polimerEvent'];
if (!siemEvent) {
siemEvent = 'complete';
}
el.addEventListener(siemEvent, function (e, options) {
expressionHandler(e.detail);
})
}
};
}]);
});
Polymer component
<dom-module id="search">
<template>
<h3>Search</h3>
<div class="input-group">
<textarea placeholder="search by expression (eg. temperature>100)"
rows="10" cols="100" value="{{text::input}}"></textarea>
<p>
<button id="button" class="btn input-group__addon">Search</button>
</p>
</div>
</template>
<script>
Polymer({
is: 'search',
properties: {
text: {
type: String,
notify: true
},
},
regularSearch: function(e) {
console.log(this.range);
this.fire('complete', {'text': this.text});
},
listeners: {
'button.click': 'regularSearch',
}
});
</script>
</dom-module>
Page
<search id="search" polimer-binding="searchData"
siem-event="complete" range="{{range}}"></siem-search>
searchData is the control function
$scope.searchData = function(searchObject) {
alert('searchData '+ searchObject.text + ' ' + searchObject.range);
}
This should work.
<div my-method='theMethodToBeCalled'></div>
app.directive("myMethod",function($parse) {
restrict:'A',
scope: {theMethodToBeCalled: "="}
link:function(scope,element,attrs) {
$(element).on('theEvent',function( e, rowid ) {
id = // some function called to determine id based on rowid
scope.theMethodToBeCalled(id);
}
}
}
app.controller("myController",function($scope) {
$scope.theMethodToBeCalled = function(id) { alert(id); };
}
I have the following code to pull some data from an external source:
$(document).ready(function(){
$.getJSON('mydata.json',function(data) {
var ned = data.names.ned;
return(ned);
});
});
And In my JSON I have:
{
"names": {
"ned": "Eddard Stark",
"jon": "Jon Snow",
"tyrion": "Tyrion Lannister"
}
}
I want to know how can I use the variable 'ned' on another function. Also, I want further to set other variables like 'jon' and 'tyrion' to be able to use later, but I can't make them pass to another function.
The JSON callback must be done on page load to be able to proper use some of the app functions, that's why it's on document ready.
You can do that easily using jquery $.Deferred:
function getNed()
{
return $.getJSON('mydata.json').pipe(function(data) {
var ned = data.names.ned;
return ned;
});
}
getNed().done(function(ned) {
alert(ned);
});
A quick/easy way to do this would be to declare a global variable, then fill it with your data from the json call when you get it.
<script>
var myJsonData; //Make this a very unique name, as you may conflict with other variables in plugins and such.
$(document).ready(function(){
$.getJSON('mydata.json',function(data) {
myJsonData = data;
var ned = data.names.ned;
return(ned);
});
});
</script>
However, note that your getJSON call could take a long time, and you have to be diligent in checking that the myJsonData variable is not undefined before using it. Alternatively, you could call some sort of initialization function from the json callback.