I can't seem to find the answer to my question or the correct angular way to do this. I understand it's partially subjective. I have an element that's clickable. Inside that element I also have another element that is clickable:
<li (click)="route($event, d, d.isdliked)" *ngFor="let d of dList; let i = index">
<div class="image-container" [ngStyle]="{ 'background-image': 'url(' + d.ImagePath + ')'}">
<div class="keep-container">
<div *ngIf="d.dliked" (click)="cantKeep()" class="liked">
<p>{{d.dLikes}}</p>
</div>
<div *ngIf="!d.dliked" (click)="keep(d, i)" class="not-liked">
<p>{{d.dLikes}}</p>
</div>
</div>
</div>
</li>
So the first click event in the li element will route the user to another page. The other to click event's do not route anywhere. But if I click on those two inner click events I get routed to my other page when I don't want to.
So I tried this little bit of code to check to see if the element that is clicked contains the class "keep-container":
route(element: Element, d: D, dIsLiked: boolean): void {
if (!element.classList.contains("keep-container")) {
this.router.navigate(['/dinfo']);
}
}
but this isn't working.
I tried with element.target of course and that didn't work. What am I doing wrong? I'll keep searching.
Main objective: If I click on the p tag
<p>{{d.dLikes}}</p> I want to check to see if it's inside the class "keep-container"
just use $event.stopPropagation() as usually you do in javascript
<div *ngIf="d.dliked" (click)="$event.stopPropagation();cantKeep()">...</div>
Well, I like in the same .html, you can pass the $event to the function cantKeep and make the stopPropagation in the .ts
<div *ngIf="d.dliked" (click)="cantKeep($event)">...</div>
cantKeep(event)
{
event.stopPropagation();
...rest of actions..
}
Related
I'm having troubles with clicking an item inside an each loop (in CasperJS) here's a small part of the code:
$("#id1",html).each(function( index ) {/*loop-start*/
var job = {};/*init*/
casperjs.click(".class2");
boo.waitForSelector('selector3', function() {
job.url = casperjs.getCurrentUrl();
page.pagejobs.push(job);
casperjs.back();
casperjs.waitForSelector('selector4', function() {
},function(){
}, 6000);
},function(){
}, 10000);
});/*loop-end*/
Basically I'm clicking a button (casper.click(".class2")) that's fine no problem here. The first time it works fine 'cause it clicks the first button with the selector (.class2) but the problem is that there are many selectors with the same class than that one (They are children of (#id1)).
So its something like:
<div id="id1">
<div class="anything">
<a button class="class2"> </a>
</div>
<div class="anything">
<a button class="class2"> </a>
</div>
</div>
So this casper.click(".class2") is my problem I think. I need a way to select the current button on each iteration of the each function. Note that I can't use $(this).
CSS selectors provide the :nth-child() pseudo-class which you can use to select a child element based on an index. This works as expected when only .anything elements are children of #selector1goeshere.
You can use
casper.click("#id1 > :nth-child("+(index+1)+") > a.class2");
You can also use XPath expressions to do this which don't have that limitation of only having .anything children. For example like this:
var x = require("casper").selectXPath;
...
casper.click(x("//*[#id='id1']/*[contains(#class,'anything')]["+(index+1)+"]/a[contains(#class,'class2')]"));
What I have in my template is just a bunch of divs and a list, consisting of multiple li elements. The use case is simple, the li elements are a dropdown and are displayed only on clicking a button. When the dropdown is visible and someone begins to type, the matching li element should be selected, or there should be a visual indication.
My approach is this, on a keyup event, I look for the typed word (this is quite easy) in the li elements. I find a few elements, which I've confirmed. Now, when I try to do something with these elements, nothing seems to happen WHILE the dropdown is open (right now, I'm trying to .toggle()) these elements. Now, when I click the button again (which showed the dropdown in the first place) (this click hides the dropdown), and then click the same button again to reveal the dropdown, voila! The values have been changed as they should be – the matching elements have been hidden/shown.
This has me stumped. For company policies, I can't upload the code up here, but I'll be very thankful if someone else has had this problem before and can help me out.
EDIT:
Code: function to change the dropdown on keypress, this is being fired correctly:
filterOptionsForKeypress: function (event) {
var typedString = this.$('input.filter-button-text').val(),
searchToken = _.trim(typedString.toLowerCase().replace(/ /g, '_')),
matchingLi = this.$("li[data-field^='" + searchToken + "']", this.$el), // makes no difference with or without the context, this.$el
that = this;
if (matchingLi && matchingLi.length) {
this.$(matchingLi[0]).html('kaka'); // this change shows only if the dropdown is hidden + shown again
console.log('trying to move focus', this.$(matchingLi[0]).attr('data-field'));
}
// this.$el.append('Some text'); -- this works, I see the changes as they happen
}
And the template looks something like this:
<div class="filter-button filter-option {{if !model.include}}button-red{{else}}button-green{{/if}} toggle-dropdown" data-dropdown-class="{{if !model.include}}button-red{{else}}button-green{{/if}}">
<div class="filter-button-text">${model.option}</div>
<div class="filter-drop"></div>
<div class="dropdown filter-dropdown">
<ul>
{{each model.config.options}}
<li data-field="${$value.op}" data-include='${$value.include}'>${$value.name}</li>
{{/each}}
</ul>
</div>
</div>
EDIT #2:
When the dropdown is open, this is how the html looks:
OPEN:
CLOSED:
So basically, apart from adding a few styles to the enclosing div and a class 'open', I don't see any differences.
The problem was that we're using a plugin for dropdown menus. So basically, what we saw on the screen wasn't what we found selecting with this.$(). The solution? Look globally and with a :visible filter voila, problem solved.
How do i even put these, let me try. In the following sets of codes, i want to click 'parentclass' and have an alert value of 'child1' and when i click the class below it which is 'Parent 2' have an alert fire with a value of 'child2'
So this must alert the content of that class only and not the entire class.
Here's some Javascript in Jquery.
var childclass = $('.childclass').html();
$('.parentclass').click(function(e) {
alert (childclass)
});
$('.childclass').click(function(e) {
e.stopPropagation()
e.preventDefault()
});
And HTML
<a href="" onClick="return false">
<div class='parentclass'>
Parent 1
<div style="display:none" class="childclass">child1</div>
</div>
</a>
<a href="" onClick="return false">
<div class='parentclass'>
Parent 2
<div style="display:none" class="childclass">child2</div>
</div>
</a>
This line var childclass = $('.childclass').html(); doesnt make sense as it doesn't know which element in particular you mean. The result of that will just be child1child2 which is just a concatenation of the .html() of all the elements with class childclass. This is obviously not what you want.
Therefore you should dynamically find the child with a class of childclass upon receiving the click event.
$('.parentclass').click(function(e) {
alert($(this).find('.childclass').html())
});
Also, you should know that your child class event handler is useless as we don't care if the event gets propogated downwards. If you DID care, then your e.stopPropagation() and e.preventDefault() should be in the event handler of the parent class.
You need to fetch the html of the clicked parent element within the click handler
$('.parentclass').click(function (e) {
alert($(this).find('.childclass').html())
});
$('.childclass').click(function (e) {
e.stopPropagation()
e.preventDefault()
});
Demo: Fiddle
Several ways you can go about this.
First, if your HTML will not be dynamic (elements already exist when page loads), then you can select elements by the parent class name and assign click event as so:
$('.parentclass').click(function(e) {
// the first variable here is selecting the inner elements having class 'childclass'
// keep in mind, if more than one child having that class is present within this parent, it will select all of them
var child = $(this).find('.childclass');
// here we alert the text of the inner child found
// if it is more than one, you will have undesired results. you may want to specify `.first()`
alert(child.text())
})
For newer jQuery you can also use $('.parentclass').on('click', function(e) {.
If you expect any pieces of parentclass to be dynamic, then you'll want to delegate the event based on either a static parent to the parents or document. This can be like so:
$(document).on('click', '.parentclass', function(e) {
alert($(this).find('.childclass').text())
})
Or, if you have a static (already there when page loads) wrapping element, give it an ID like `parentClassWrapper' and assign the click event dynamically as:
$('#parentClassWrapper').on('click', '.parentclass', function(e) {
alert($(this).find('.childclass').text())
})
Some helpful links:
jQuery API
jQuery Selectors
.click()
.on()
Some info on Event Delegation
jquery on vs click methods
jQuery .on('click') vs. .click() and .delegate('click')
jquery .live('click') vs .click()
I made several adjustments to your html that are worth noting. There's no need for the <a> tag. Don't use inline js - onlick in your html. Note that I wrapped the text inside of the div in the <a> tag instead. This markup is more semantic. Also, move your styles to css rather than in the html.
<div class="parent">
<a>Parent 1</a>
<a class="child">child of parent 1 contents</a>
</div>
<div class="parent">
<a>Parent 2</a>
<a class="child">child of parent 2 contents</a>
</div>
css:
.parent > .child { /* good practice: only select an immediate child of the parent */
display: none;
}
The other answers here are using find() to select the child, but I recommend children() instead. For example, if you had additional nested .childs, find() will select them all, but children() will only select direct .childs of the parent, so it is better in this case. I also recommend using the console for debugging rather than alert.
Live demo here (click).
$('.parent').click(function() {
var $child = $(this).children('.child');
var cls = $child.attr('class');
console.log(cls);
$child.show(); //added so that you can click the child
});
$('.child').click(function() {
var html = $(this).html();
console.log(html);
//if you just want the text, use this instead:
var text = $(this).text();
console.log(text);
});
I have multiple containers that I need to animate.
Basically: you click on class: box-n (e.g. box-1) and you slideToggle: box-child-n (e.g. box-child-1).
Instead of a click function for every box-n to toggle box-child-n, I want a simple line of code that matches box-n with its children class.
html:
<div class="box-1">Some clickable container</div>
<div class="box-child-1">This should toggle when box-1 is clicked</div>
<div class="box-2">Some clickable container</div>
<div class="box-child-2">This should toggle when box-2 is clicked</div>
Et cetera...
current jquery:
$('.box-1').click(function() { $('.box-child-1').slideToggle() });
$('.box-2').click(function() { $('.box-child-2').slideToggle() });
Sort of desired jquery (allInt function is made up.):
var $n = allInt();
$('.box-' + n).click(function() {
$('.box-child-' + _n).slidetoggle() // local variable to inter alia .box-1
})
I can't seem to think of any solution, so I am asking for help once again.
I appreciate every suggestion you folks give me!
Here's one way to do it that allows for the elements to have other classes besides the ones that you're using to pair them up:
$('div[class*="box-"]').click(function() {
var c = this.className.match(/\bbox-\d+\b/);
if (c)
$('div.' + c[0].replace(/-/, '-child-')).slideToggle();
});
Demo: http://jsfiddle.net/6xM47/
That is, use the [name*=value] attribute contains selector to find any divs with a class attribute that has "box-" in it somewhere. Then when clicked extract the actual class and check that it matches the "box-n" pattern - this allows for multiple (unrelated) classes on the element. If it does match, find the associated "box-child-n" element and toggle it.
Having said all that, I'd suggest structuring the markup more like this:
<div data-child="box-child-1">Some clickable container</div>
<div class="box-child-1">This should toggle when box-1 is clicked</div>
...because then the JS is simple and direct:
$('div[data-child]').click(function() {
$('div.' + $(this).attr('data-child')).slideToggle();
});
Demo: http://jsfiddle.net/6xM47/1/
To just answer your question, this will do the trick :
$("div[class^='box-']").click(function(){
$(this).parent().find('.' + $(this).attr('class').replace('-','-child-') ).slideToggle();
});
jsfiddle here.
Anyway i dont think you use a good approach (you may wrap child into parent div or use ids).
I am trying to use a jQuery listener to listen for a users clicks on the html body and perform a specific function if anywhere on the body has been clicked except for a specific div and the children within that div.
The idea is that the div is a popup type element and instead of having to have a close button that the user can click, they should just be able to click anywhere on the page besides that div and it will automatically close.
I have been using this listener:
var initialClick = false;
$('body').on('click.addPhoneListeners', function(event) {
var target = EventUtility.getTarget(event);
if(initialClick) {
if(target.parentNode.id != clone.id && target.id != '') {
finish();
};
}
initialClick = true;
});
Which listens for all clicks on the body and unless the click comes from within the element I want the user to be able to interact with, it closes. Unfortunately this only works with a div that has only one level of children. As soon as I start getting multiple hierarchies such as this:
<div id="addressContainer">
<div id="address" class="hidden row">
<div class="row">
<div id="address.primary" class="hidden">P</div>
<div id="address.type"></div>
<div id="address.street"></div>
<div id="address.editButton" class="hidden"><a id="addressEditButton">Edit</a></div>
<div id="address.deleteButton" class="hidden"><a id="addressDeleteButton">Delete</a></div>
</div>
<div class="row">
<div id="address.city"></div>
<div id="address.state"></div>
<div id="address.zip"></div>
</div>
<input type="hidden" id="address.id"></input>
</div>
</div>
The target.parentNode.id gives me the objects parent element as opposed to the addressContainer id and thus does not work. Is use the top level parent from within nested elements? Other elements will be using this same code, so it has to work on both divs with just one level and div's with multiple.
UPDATE: Found a few excellent solutions, thanks guys. I do however have one other question. Refer to my code above where I set an initialClick boolean to false, then set it to true. I am doing this because for some reason if I don't, when I go to add the popup div, the initial click from the button used to set that popup fires the listener and closes the popup before I have a chance to do anything. This has been my solution around the problem, but is that the only way? Or am I just setting the listener slightly incorrect?
I usually do something like this:
$(document).click(function(e) {
// hide popup
});
$('#popup_div').click(function(e) {
e.stopPropagation();
});
That way the clicks from your popup never propagate to the document, so the close function never fires.
Replace
if(target.parentNode.id != clone.id)
with
if ($(target).closest("#" + clone.id).length === 0)
(I left the second clause alone since it didn't seem related to your question.)
This tries to find the closest ancestor with ID equal to clone.id. If none is found, an empty jQuery object is returned (i.e. one with length === 0), which is what we test for.
Incidentally: jQuery normalizes event.target, so you can just use that instead of whatever custom monstrosity EventUtility.getTarget(event) embodies.