I need to get a href value after click. My code looks like this:
$('.menu a').click (event) =>
event.preventDefault()
console.log($(this).attr('href')) # it returns 'undefined'
What am I doing wrong?
[edited]
My html code:
<div class="menu">
All
</div>
This is because of the subtle difference in Coffeescript between => and ->
In JavaScript, the this keyword is dynamically scoped to mean the
object that the current function is attached to. If you pass a
function as a callback or attach it to a different object, the
original value of this will be lost. If you're not familiar with this
behavior, this Digital Web article gives a good overview of the
quirks.
The fat arrow => can be used to both define a function, and to bind it
to the current value of this, right on the spot. This is helpful when
using callback-based libraries like Prototype or jQuery, for creating
iterator functions to pass to each, or event-handler functions to use
with bind. Functions created with the fat arrow are able to access
properties of the this where they're defined.
http://coffeescript.org/
This is why this is binded to window.
You should use:
$('.menu a').click (event) ->
event.preventDefault()
console.log($(this).attr('href')) # it returns the link !
Related
I have a section of my view (html) that is generated programmatically by a viewmodel/class. This uses the Aurelia DOM (Aurelia Docs - pal :: Dom) functionality to generate and add the raw HTML elements to the view.
However, I am unable to get events within the generated html to call back to the viewmodel. An example:
let deleteButton = this.dom.createElement("button");
deleteButton.setAttribute("onclick", "cancelCreditNote(`${ row.creditNoteId }`)");
A click on the generated button won't call back to the viewmodel, which does have a cancelCreditNote function. Various other things like deleteButton.setAttribute("click.delegate", "cancelCreditNote('${ row.creditNoteId }')"); do not work either.
Does anyone know how to access a viewmodel class from essentiall 'raw' html in aurelia?
Unfortunately in this instance I cannot use the standard aurelia templating to generate the HTML.
The DOM property on PAL is just an abstraction for the browser's DOM object, create element is likely just calling document.createElement which doesn't afford any Aurelia binding to the created element.
You could try using aurelia.enhance(context, element) which takes an existing DOM element and runs it through the templating engine.
With this method you can also pass a binding context to apply to the element.
In my HTML I use this:
<div id="collapsesidebar" click.delegate="toggleSidebar()">
In my view-model I have this method:
toggleSidebar(){
alert('hi');
}
You could also do this from your view-model with JQuery like this:
attached() {
$('main').on('click', ()=> alert('hi'));
}
The last option is ONLY available áfter the attached() method is triggered: before that the binding needs to do its job and only after that the elements are located inside of the dom.
In other words: this will not work:
activate(){
$('main').on('click', ()=> alert('hi'));
}
because the constructor and the activate method both get fired before the attached method.
React Developer Tools give a lot of power to inspect the React component tree, and look at props, event handlers, etc. However, what I'd really like to do is to be able to inspect those data structures in the browser console.
In chrome I can play with the currently selected DOM element in the console using $0. Is there a way to extract React component info from $0, or is it possible to do something similar with the React Dev Tools?
Using React Developer Tools you can use $r to get a reference to the selected React Component.
The following screenshot shows you that I use React Developer Tools to select a component (Explorer) which has a state-object callednodeList. In the console I can now simply write $r.state.nodeList to reference this object in the state. Same works with the props (eg.: $r.props.path)
An answer to your question can be found here in a similar question I asked:
React - getting a component from a DOM element for debugging
I'm providing an answer here because I don't have the necessary reputation points in order to mark as duplicate or to comment above.
Basically, this is possible if you are using the development build of react because you can leverage the TestUtils to accomplish your goal.
You need to do only two things:
Statically store the root level component you got from React.render().
Create a global debug helper function that you can use in the console with $0 that accesses your static component.
So the code in the console might look something like:
> getComponent($0).props
The implementation of getComponent can use React.addons.TestUtils.findAllInRenderedTree to search for match by calling getDOMNode on all the found components and matching against the passed in element.
Open console (Firefox,Chrome) and locate any reactjs rendered DOM element or alternatively execute js script to locate it:
document.getElementById('ROOT')
Then check for element properties in object property viewer for attributes with name beginning like '__reactInternalInstace$....' expand _DebugOwner and see stateNode.
The found stateNode will contain (if it has) 'state' and 'props' attributes which is used heavily in reactjs app.
Though the accepted answer works, and is a great method, in 2020 you can now do a lot of inspection without using the $r method. The Components tab of React DevTools will show you props and detailed state when you select the relevant component (make sure you're on the right level), as well as let you do other things like suspend it or inspect the matching DOM element (little icons in the top right).
Assign the state or prop object to the window object:
window.title = this.state.title
And then from the dev tools console you can try different methods on the exposed object such as:
window.title.length
8
You can attach a reference to the window object like
import { useSelector } from "react-redux";
function App() {
// Development only
window.store = useSelector((state) => state);
return (
<div className="App">
</div>
);
}
export default App;
Then access it from the console
store
{states: {…}}
states:
someProperty: false
[[Prototype]]: Object
[[Prototype]]: Object
[Console][1]
[1]: https://i.stack.imgur.com/A4agJ.png
I am trying to implement something which I hope is relatively straight forward... I have one component (lets call it the wrapper component) which contains another component (lets call it the inner component) inside it via the data-sly-resource tag:
<div data-sly-resource="${ 'inner' # resourceType='/projectname/components/inner' }"></div>
I would like to pass in some additional parameters with this tag, specifically a parameter that can be picked up by sightly in the inner component template? I am trying to specify whether the inner templates outer html tag is unwrapped based on a parameter being passed in when the component is called via data-sly-resource.
After experimenting and perusing the sightly documentation, I can't find a way of achieving this.
Does anyone know if this is possible?
Many thanks,
Dave
You can use the Use-API to write and read request attributes if the alternatives proposed here don't work for you.
A quick example of two components where the outer component sets attributes that are then displayed by the inner component:
/apps/siteName/components/
outer/ [cq:Component]
outer.html
inner/ [cq:Component]
inner.html
utils/ [nt:folder]
setAttributes.js
getAttributes.js
/content/outer/ [sling:resourceType=siteName/components/outer]
inner [sling:resourceType=siteName/components/inner]
/apps/siteName/components/outer/outer.html:
<h1>Outer</h1>
<div data-sly-use="${'../utils/setAttributes.js' # foo = 1, bar = 2}"
data-sly-resource="inner"></div>
/apps/siteName/components/inner/inner.html:
<h1>Inner</h1>
<dl data-sly-use.attrs="${'../utils/getAttributes.js' # names = ['foo', 'bar']}"
data-sly-list="${attrs}">
<dt>${item}</dt> <dd>${attrs[item]}</dd>
</dl>
/apps/siteName/components/utils/setAttributes.js:
use(function () {
var i;
for (i in this) {
request.setAttribute(i, this[i]);
}
});
/apps/siteName/components/utils/getAttributes.js:
use(function () {
var o = {}, i, l, name;
for (i = 0, l = this.names.length; i < l; i += 1) {
name = this.names[i];
o[name] = request.getAttribute(name);
}
return o;
});
Resulting output when accessing /content/outer.html:
<h1>Outer</h1>
<div>
<h1>Inner</h1>
<dl>
<dt>bar</dt> <dd>2</dd>
<dt>foo</dt> <dd>1</dd>
</dl>
</div>
As commented by #AlasdairMcLeay, this proposed solution has an issue in case the inner component is included multiple times on the request: the subsequent instances of the component would still see the attributes set initially.
This could be solved by removing the attributes at the moment when they are accessed (in getAttributes.js). But this would then again be a problem in case the inner component is split into multiple Sightly (or JSP) files that all need access to these attributes, because the first file that accesses the request attributes would also remove them.
This could be further worked-around with a flag telling wether the attributes should be removed or not when accessing them... But it also shows why using request attributes is not a good pattern, as it basically consists in using global variables as a way to communicate among components. So consider this as a work-around if the other two solutions proposed here are not an option.
There is a newer feature that request-attributes can be set on data-sly-include and data-sly-resource :
<sly data-sly-include="${ 'something.html' # requestAttributes=amapofattributes}" />
Unfortunately it doesn't seem to be possible to construct a Map with HTL (=Sightly) expressions, and I don't see a way to read a request attribute from HTL, so you still need some Java/Js code for that.
unfortunately, no. there is no way to extend sightly functionality. you cannot add new data-sly attributes or modify existing ones. The best you can do is write your own helper using the USE API
If you just need to wrap or unwrap the html from your inner component in different situations, then you can just keep the html in the component unwrapped, and wrap it only when needed by using the syntax:
<div data-sly-resource="${ 'inner' # resourceType='/projectname/components/inner', decorationTagName='div', cssClassName='someClassName'}"></div>
If you need more complex logic, and you need to pass a value to your inner component template, you can use the selectors. The syntax for including the resource with selectors is:
<div data-sly-resource="${ 'inner' # resourceType='/projectname/components/inner', selectors='mySelectorName'}"></div>
The syntax to check the selectors in the inner component is:
${'mySelectorName' in request.requestPathInfo.selectorString}"
or
${'mySelectorName' == request.requestPathInfo.selectorString}"
I'm trying to define a click handler in a Mootools class. My handler presumes opening a block of links, each of which should be 'equipped' with its own click handler, which should trigger a link specific action. What I mean is let's suppose I have the following HTML code:
<div id="wrapper">
open options
<div class="optionsBlock" style="display:none">
1
2
3
</div>
</div>
Then I'm trying to define a class like this in Mootools:
var myHandler = new Class({
Implements : [Events],
initialize : function(element){
this.element = document.id(element);
this.elements = this.element.getChildren('a');
this.elements.addEvents('click', function(ev){
ev.preventDefault();
//'this' as a reference to the current element in the array, which is being clicked, correct?
this.getSibling('div.optionsBlock').setStyle('display', 'block');
var parentLink = this;
this.getSibling('div.optionsBlock').getChildren('a').addEvent('click', function(e){
e.preventDefault();
//should append the text of currently clicked link into the parent link
parentLink.appendText(this.get('text'))
});
});
}
});
new myHandler('wrapper');
This is just an illustration of how I can imagine the code should be like (and I'm sure this code is not good at all), but I really need some help regarding the following:
Since adding new events constatly changes the scope of 'this', how should I keep a reference both to the class instance and the element being clicked?
How should I modify the class in order not to have the entire code inside the initialize method? I tried to create separate methods for every event handler, but as a result I got confused with the scope of 'this', with binding and trying to get all of this together really annoys me, but I want to get a grip of this knowledge.
How to keep track of the scope of 'this' when adding nested event handlers inside a class? I honestly googled and searched for an answer but for no avail.
Thanks!
scope, take your pick - asked many many times - search here for [mootools]scope this:
Mootools class variable scope
mootools variable scope
Mootools - Bind to class instance and access event object
to recap:
use a saved reference var self = this; then reference self.prop or use the fn.bind pattern
add more methods. follow single responsibility principle. eg, in your class, create attachEvents: function() {} and have initialize call that.
by using the saved reference pattern. you can fix it upriver by delegating events as opposed to creating new event callbacks on parent clicks.
I'm trying to process all select elements with a specific data- attribute set.
I've got the loop working to pick up the element, but whenever I try to find the value of its other data- attributes I get undefined error messages.
Here is the loop:
$('select[data-hm-observed="1"]').each(function(idx, sel) {
alert(sel.getAttribute('data-hm-url'));
alert(sel.data('hmUrl'));
});
In the loop the first alert works, but the second produces:
TypeError: 'undefined' is not a function (evaluating
'sel.data('hmUrl')')
If I use the Safari console I can get the select object, put it in a variable, and interrogate its data- attributes without issue.
It seems that the .each() is having an effect on the sel variable contents - but I can't understand what.
Using JQuery 1.7.1
UPDATE:
Just discovered that if I change the loop so that it explicitly gets the element again, it all works:
$('select[data-hm-observed="1"]').each(function(idx, sel) {
xx = $(sel);
alert(sel.getAttribute('data-hm-url'));
alert(xx.data('hmUrl'));
});
Is this the correct solution?
Can I infer from this that the element passed into the loop by .each hasn't been 'processed' by jquery, and that I have to pull it myself via $(...) so that jquery does its stuff to it - this doesn't feel right - but its working.
sel is a DOM Object here, not equipped with the abilities of a jQuery Object. First, you should turn this DOM Object into a jQuery Object like this:
alert( $(sel).data('hmUrl') );
Alternatively, you can also use $(this).data('hmUrl'), because this will refer to sel (the current DOM element in the iteration).
See also .each() 2nd Example