Angular - execute code AFTER *ngIf has shown the element - javascript

In my application I have a help section that is only visible when this.car.helpOpen property is true, and initially the property is false:
<ion-item *ngIf="car.helpOpen">
<div class="car-help-content" item-content>
<img src="{{testURL}}" />
<p class="explanations" [innerHTML]="car.helpText"> </p>
</div>
</ion-item>
I have a method that changes the value of this.car.helpOpen to true and after that adds an event handler to all of the <a> elements(car.helpText contains <a> elements) inside the <p> element:
toggleHelp(input){
input.helpOpen=!input.helpOpen;
$("p.explanations").find("a").click(function(e){
alert(e.target.innerHTML);
});
}
But I think that the attachment of event handlers is happening before the *ngIf actually shows the help section, and that's why the event handlers don't get attached. If I remove *ngIf completely and execute the function toggleHelp(), the handlers get attached.
Is there a way I can work around this?
Maybe there is a way to add the event handlers without using jQuery? (without changing the actual innerHTML of the element)

ngIf is a structural directive, it creates/destroys content inside the DOM. you can hide the elemnt by css like add class will make the display:none
What is the difference between *ngIf and [hidden]
You can add a click event to p elemnt and check the target element if it 's a this will look like add event listener to a element with pure javascript without jquery
template
<p [innerHTML]="html" (click)="toggleHelp({},$event)"></p>
toggleHelp function
toggleHelp(input , e:MouseEvent) : void{
input.helpOpen=!input.helpOpen;
console.log('event element',e);
if ((e.target as HTMLElement).tagName === 'A') {
let target = e.target as HTMLElement;
// everything here will run if you click on a element
alert(target.innerHTML)
}
}
stackblitz example

Related

Why does prop('outerHTML') strip events, and how can I prevent it?

const continueButton = $("<button>Doesn't work.</button>").click(() => {alert("hello")});
$(".content").append(continueButton.prop('outerHTML'));
$(".content").append ($("<button>Works.</button>").click(() => {alert("hello")}))
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="content">
</div>
The reason I'm asking this question is because I need to pass the string version of some HTML to a function. For that reason, I can't use .append. but when i use the code above, it seems that the click event no longer works.
How can I get the HTML as a string, but have the click event still work?
More context: I am using a library that expects me to add HTML to it as a string. But I want to add HTML with a button on it that functions when it's clicked. I'm using jQuery to create the HTML, but when I try to pass the HTML string to the library, the buttons don't function.
You can delegate the event to the content element and use button as target selector
// add delegated event listener before inserting buttons
$('.content').on('click', 'button', (e) => console.log($(e.target).text()))
const continueButton = $("<button>Doesn't work.</button>");
$(".content").append(continueButton.prop('outerHTML'))
.append ("<button>Works.</button>");
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="content">
</div>
In line 1 the object has an event attached to it but this isn't reflected in HTML. Therefore when you add the outerHTML to an element, the browser creates a new element but events are not defined in the HTML so they don't exist.
If you embed the script inside the button HTML then it will work when you apply this HTML in different places: $('<button onclick="alert(\'hello\');">Test</button>').

When a `label` element contains a child `span`, clicking the label triggers on the child but not the parent

In this example, I've created a label group with a header, and have attempted to attach a click listener to each label; I eventually want an input inside each label, but it is not necessary to illustrate the behavior I don't understand.
I am seeing different behavior depending on whether I wrap the label text in a span tag:
When the label without a child span is clicked, the event handler is called once as I would expect, on the label element.
When the label with a child a span is clicked, the event handler is still called only once, but this time for the child span and not for the parent label.
I would have expected, in the second scenario, the event handler to trigger twice: once for the parent label, and once for the child span. Can someone explain why the addition of this span element seems to be preventing the event handler from propagating to the parent label?
var settingsGroup = document.getElementById("settings");
settingsGroup.querySelectorAll('.setting').forEach(function(setting) {
var options = setting.querySelectorAll('label');
options.forEach(function(option) {
option.addEventListener("click", function(ev) {
console.log(`${this.id} clicked: ${ev.target.tagName}`);
});
});
});
<div id="settings">
<div class="setting" role="group">
<div id="header">
<em>
A setting
</em>
</div>
<label id="option-a">
Option A
</label>
<label id="option-b">
<span>
Option B
</span>
</label>
</div>
</div>
This is normal. e.target is the element that was the target of the event (the span in the case of <label><span>...</span></label>. The target of the event is the span, and then the event propagates (bubbles) to its parent label, where it gets handled by your event handler.
If you want to look at the label instead, either use this as you have for id, or use e.currentTarget (the element the event is currently being delivered to).
This diagram from the old DOM3 Events spec is handy for understanding event flow:
You can use "pointer-events" CSS directive to stop span HTML elements receiving mouse events.
span
{
pointer-events: none;
}

Bind an html event to a function

How do I bind an html event such as onclick to a function myFunc(e){}?
I do not want to use document.getElementByClass or Id.
I do not want use jQuery.
Try this:
document.getElementsByTagName('body')[0].addEventListener('click', function(){alert("you clicked on the page")})
This adds an event listener to the body tag. Once you click on the page, it will fire the alert function.
You can get the elements by either class name, id and/or tag name:
document.getElementById('someId')
document.getElementsByClassName('someClassName')
document.getElementsByTagName('body')
Keep in mind, the "getElementsByClassName" and "getElementsByTagName" return arrays, so you might want to add the index like this
getElementsByTagName('body')[0]
document.getElementsByClassName('someClassName')[1]
...
If it's still the 1990s where you are and jQuery hasn't been invented, then sure:
<div onclick="myFunc">
</div>
First you must find the element on the page, for example var element = document.getElementById('clickme'), then you must add a listener to the click event element.addEventListener('click',function)

AngularJs ng-click $event passes child element as target

For each td element in a table I have an attached ng-click. Here is the (simplified) html for each table cell:
<td ng-click="cellClicked($event)">
<span ng-if="!cellEdit">{{event.eventName}}</span>
<input type="text" ng-if="cellEdit" ng-model="event.eventName">
</td>
And my (simplified) ng-click function:
scope.cellClicked = function (event) {
rowScope.cellEdit = true
angular.element(event.target).find('input').focus()
}
Its my goal to:
User clicks a table cell
Cell changes to "edit mode"
Give focus to the input element located inside the td.
Right now this is working as long as the user clicks inside the td element but not on the span element:
console.log(angular.element(event.target)) #--> [td...] (as desired)
However if the user clicks on the span element within the td:
console.log(angular.element(event.target)) #--> [span...]
In this use case assigning focus does not work. I was hoping to access the parent element of the span doing something like:
angular.element(event.target.closest('td'))
or
angular.element(event.target.parentNode)
But it appears when an element gets passed through via $event and accessed there is no parent context.
How can I either:
Prevent clicking the span element firing the td's ng-click
On click of span element pass through it's html parent
Changing:
angular.element(event.target)
to:
angular.element(event.currentTarget)
fixed my issue.
It seems to me using event.currentTarget is preferred to event.target in the majority of usage cases.
event.target.closest('td') won't work because event.target is a DOM element and it doesn't have method closest. You need to create a jQuery object to use this method.
Try to find closest td like this:
angular.element(event.target).closest('td')
In Angular 7.x
myClickHandler($event) {
this.selectedElement = <Element>$event.target.closest('.list-item');
}
html:
<div class="list-item" (click)="myClickHandler($event)">...</div>

Function for adding and removing style on click and unfocus

I am trying to implement a function which changes style of element on click and remove it when unfocus. For ex: When element2 is clicked, it should remove class of other elements, and add class to the clicked element only.
<div class="dope" id="element777"></div>
<div class="dope" id="element2"></div>
<div class="dope" id="element11"></div>
<div class="dope" id="element245"></div>
<div class="dope" id="element60"></div>
.....(More are created automatically, numbers are not estimatable)
I couldnt know the element ids that are created. The only remains same is class.
I have tried this, but its an unprofessional approach.
$('#element1').click(function(){
$("#element1").addClass(dope2);
$("#element2").removeClass(dope);
$("#element3").removeClass(dope);
$("#element4").removeClass(dope);
});
$("#element1").blur(function(){
$("#element1").removeClass(dope);
});
$('#element2').click(function(){
$("#element2").addClass(dope2);
$("#element1").removeClass(dope);
$("#element3").removeClass(dope);
$("#element4").removeClass(dope);
});
$("#element2").blur(function(){
$("#element2").removeClass(dope);
});
What is the best approach for automating this function, instead of adding click and blur (unfocus) function to ALL of elements ?
You can listen for click events on any div with an id containing the word "element', then target its siblings elements (those that are not clicked, without referring to them by id). This might do it:
$("div[id*='element']").click(function(){
$(this).addClass('dope').siblings('.dope').removeClass('dope');
});
Your jQuery could be vastly simpler if you leverage this and siblings:
Instead of:
$("#element1").addClass(dope2);
$("#element2").removeClass(dope);
$("#element3").removeClass(dope);
$("#element4").removeClass(dope);
It could be:
$('.dope').click(
function() {
$(this).addClass(dope2).siblings().removeClass(dope);
}
);
NOTE:
Do you have a variable called dope with the class name, or is dope the class name? If it's the classname, you need to put it in quotes: $(this).addClass('dope2'), etc.
If you are removing the class dope, then will want to add a class you can always use to select these elements (so that when you remove dope, it continues to work).
Button part:
$("div").click(function(){
if($(this).hasClass("dope") || $(this).hasClass("dope2")){
$(this).addClass("dope2");
$(".dope").not($(this)).removeClass("dope");
}
})
Blur part:
$("div").blur(function(){
if($(this).hasClass("dope") || $(this).hasClass("dope2")){
$(this).removeClass("dope");
}
}
I would recommend using the :focus css selector rather than using javascript to do what you are doing... Read more here. Instead of having a click listener, the focus selector will take care of that for you and automatically remove the styling when the element is out of focus.

Categories

Resources