Vue.js - using v-el inside v-for doesnt work - javascript

I want to animate certain divs inside v-for loop on click event. For that i need to have dom/jquery elements to work on. Of course i dont want to animate all elements at once, just these specific ones i click.
I wanted to use v-el to achive this, but it doesnt work, $els object doesnt return anything. This is what i tried:
<li v-for="element in elements" v-el="li">
<span v-el="span">lorem</span>
<span v-el="span2"> ipsium {{element.content}}</span>
</li>
https://jsfiddle.net/w1cd96ux/

v-el doesn't work on or within a v-for. If each <li> is a component you can use v-ref though then you'd have access to each span through v-el (which is deprecated in the next version of Vue).
I'd probably just take this approach, if I'm understanding correctly:
<li v-for="item in items" #click="animate">
<span>...</span>
<span>...</span>
</li>
Then in your methods you can do:
methods: {
animate(event) {
const li = event.currentTarget
const spans = li.querySelectorAll('span')
...
}
}

Two things:
Correct way to define v-el as per latest version is v-el:span. check this link https://vuejs.org/api/#v-el
your this inside ready method points to top level div so if you put the v-el at top level and try to print in ready function, it will print.
check this jsfiddle
https://jsfiddle.net/oyomyosw/

Related

Updating DOM (JavaScript)

I have a problem with updating DOM. Probably it's not hard to do for experienced developers.
I made a carousel with 4 items and all of them are shown by default.
For example, when clicking on the < LEFT ARROW I need to replace the first item with the next one, and the first one must be pushed as the last one. The same logic for the right arrow >
I get my carousel like this:
const carouselItems = Array.from(document.querySelectorAll('.carousel-item'));
Also the function for replacing the items:
function carouselToLeft() {
carouselItems.push(carouselItems.shift());
}
So my caroueslItems array changes as expected but I can't make the DOM to update. Somebody help with this please. I'm not experienced as you guess, but I need the answer for now.
Here is a solution with using only a single constant and no variables or arrays:
const cont=document.querySelector(".container");
document.querySelectorAll("button").forEach(b=>b.onclick=ev=> // assign click events
cont[(b.textContent=="<"?"pre":"ap")+"pend"]( // prepend() or append()
cont.children[b.textContent=="<"?cont.children.length-1:0]) // last or first child-element
)
<h2>A simplified carousel</h2>
<div class="container">
<div class="carousel-item">one</div>
<div class="carousel-item">two</div>
<div class="carousel-item">three</div>
<div class="carousel-item">four</div>
<div class="carousel-item">five</div>
</div>
<button title="move last element to the top"><</button>
<button title="move first element to the bottom">></button>
The reason why I get away with so little code is that when we append() or prepend() a DOM element it will be taken away from its original position. So, no need to "clean up". And by looking freshly at the children-collection of .container I am always up-to-date with the current state of the carousel.
Array.from create a new Array Object that whatever you do on it can make DOM update itself.
You can get an Array-like object by using document.querySelectorAll, then push each item of it to a true Array.
Then, while you want to replace the first item with the next one, you can remove it, then append to the parent element of it.

Getting The Source Element From Click Event Handler In Angular

I am still new to Angular and I'm struggling to get the DOM Element of an Angular Click Listener.
What I have is the following component HTML:
<div *ngFor="let menuItem of menu; index as itemId" class="menuItem">
<div class="menuItem__top" (click)="itemClicked($event, !!menuItem.submenu)">
<!-- Additional divs inside... -->
</div>
</div>
I would like to toggle a class of "menuItem__top" when it is clicked. My approach was to use a click event listener but I can't get the source Element to apply the class on.
itemClicked(event, hasSubmenu){
console.log(this) //is the component
let target = event.target || event.srcElement || event.currentTarget;
if(hasSubmenu){
console.log(target);
}
}
It could be done by getting the target of the $event but this way I would need to check the target and move with closest(".menuItem__top") up to the correct source element.
Is there an easy way in Angular to pass the source element of the click listener to the click function or a way to get it inside the click function?
In vanilla JS it would be as easy as using "this" inside the click function, but in Angular this is bind to the component. (In this case, it would be ok to loose the binding to the component if this is the only way.)
I thought about two ways:
Assigning a dynamic reference containing some string and the itemId, passing the itemId and retrieving the reference object based on the itemId in the listener.
Using a #HostListener to listen on every "menuItem__top" click and toggling the class every time.
What do you think is the best way? I feel like I am missing something simple here.
Go the other way around. People are used to jQuery and the way it works (selecting elements already present in the DOM, then adding them a class). So in Angular, they try to do the same thing and grab the element that was clicked, to apply it a class. Angular (and React and others) work the other way around. They construct the DOM from data. If you want to modify an element, start with modifying the data it was generated from.
This <div class="menuItem__top"> that you click on is constructed from let menuItem. All you have to do is add a property, say "isClicked" to menuItem.
<div *ngFor="let menuItem of menu; index as itemId" class="menuItem">
<div class="menuItem__top"
[class.isClicked]="menuItem.isClicked"
(click)="menuItem.isClicked = true">
<!-- Additional divs inside... -->
</div>
</div>

Change CSS of element not in DOM

I have an element, let's say a circle.
And there is a list of item in a list view.
Initially, the circle is not rendered. I have set its CSS display property to none, and instead select an item message is displayed. The idea is when the user selects an item from the list, I want to show the circle changing its background-color property associated with selected item.
My approach is something like this
itemSelected(item) {
const itemtColor = item.color;
$('#selected-item-color').css('background-color', itemColor);
}
The issue is:
As the element is not present in the DOM when I try $('#selected-item-color'), it will return an empty list, and the change of property does not do anything. But on next subsequent selections, it works fine.
So, is there any clean way to do this before the element is actually rendered in the DOM either jQuery or JavaScript. Or, should I just look for a way to do this after the element is rendered, which I'm not sure if there is a way with my problem.
Any help is appreciated, thanks!
Edit:
I have the HTML code written in handlebars
The code calling above function
<div class="item-list-content">
{{#each itemList as |item|}}
<div class="list-item" {{action "itemSelected" item}}>{{item.name}}</div>
{{/each}}
</div>
The dynamic content
<div class="item-details">
{{#if selecteditem}}
<div id="selected-item-color"></div>
{{else}}
<div class="item-details-message">Please select an item</div>
{{/if}}
</div>
To solve your problem you can just use ngShow instead of ngIf. There are better ways to do that as well, but for your issue ngShow will solve your problem.
I tried out few things and could not get anything to solve this.
So, I ended up doing the next best thing:
Putting the code to change project color inside a timeout function.
A timeout of 1ms worked for me, however I have not tested it well, and to be on a safer side, an interval of 10ms should work without problems.
setTimeout()

ng-click is not working with any of my divs

I have a simple un-ordered list populated with ng-repeat and I want something to happen every time a user clicks on one of the list items. However, ng-click doesn't seem to be working with any of the divs inside my html, it only works with buttons. At first I thought the issue would be with the ng-repeat but it turns out that even outside of the ng-repeat ng-click does not seem to work. I have tried using ng-mousedown as well, and it doesn't seem to be working either.
Here is my html:
<div class="noteItem" ng-mouseleave="btnShow = false" ng-mouseenter="btnShow = true" ng-click="alert('click');">
<li>
{{note.subject|removeHTML}}<a ng-show="btnShow" ng-click="deleteNote(note._id)"><i>DELETE</i></a>
</li>
</div>
I have tried wrapping another div outside of this div as well but it still didn't work. I have been stuck on this problem for about an hour now.
You have ng-click in div and also in <a> element, the one being executed is in the <a> element not the ng-click in div.
Try to add div like this and try to click.
<div ng-click="yourScopeMethodHere()">click me</div>
BTW, directly calling JS alert() in ng-click will not work.
When the ng click get executed it looks for scope function and expressions. alerts and console logs neither of it so it won't get executed like this. What you can do is create a scope function and call the alert inside that function.
As you have a ng-click on the parent element (<div>) as well, the click will be triggered on both. You can cancel parent ng-click on the child with $event.stopPropagation().
<div ng-mouseleave="btnShow = false" ng-mouseenter="btnShow = true" ng-click="alert('click');">
<li>
{{note.subject|removeHTML}}
<a ng-show="btnShow" ng-click="$event.stopPropagation(); deleteNote(note._id)"><i>DELETE</i></a>
</li>
</div>
As a side note, ng-click="alert('click') will seek for $scope.alert(), if you are hoping to open the JavaScript basic alert... ;-)

does jQuery's html() remove all data attached to elements that are replaced?

I'm displaying a tabbed interface with the help of jQuery. When you click a tab, a ajax call will replace all html from a $(".content") element with new html, using something like
$(".content").html(response);
When I do this, are all jquery events and functions that are attached to elements inside the .content div removed? Is it ok to fire these events and functions again after I replace the HTML ? If I click the tabs 324523452354 times, will it duplicate jQuery data every time?
Yes. They will be removed. You can use the live event to attach to elements that dont exist yet.
$(".myElementClass").live("click", function (e) {
e.preventDefault();
//do stuff
});
In this case, this function will always be called on myElement no matter when it is injected into the DOM.
All HTML inside of your selector is replaced with the parameter you pass in, implying it is completely removed from the DOM. Meaning if you have:
<div id="mine">
<ul>
<li>One thing</li>
</ul>
</div>
And I do a call as such:
$('div#mine').html("hey");
My HTML will then be:
<div id="mine">
hey
</div>
As you can see the is completely removed and all its bound events mean nothing. If you use the jQuery.live() binding instead however, then elements that don't yet exist can have events associated with them. Meaning if you add some elements to the DOM then they events will still work, without you have to rebind if you add more, or replace them.
**.live** events are binded at the document level , read the following document which is really useful
http://www.bennadel.com/blog/1751-jQuery-Live-Method-And-Event-Bubbling.htm

Categories

Resources