How to modify the class attribute in ng-repeat module? - javascript

Here is my plunker.enter link description here
I'm a newer to AngularJS and I want to modify the class style of the star to show if it's marked.
<div class="col-sm-6 col-md-4 col-lg-4 cell-project" ng-repeat="project in projects">
<div class="panel panel-primary panel-project">
<div class="panel-heading" ng-switch="project.PermissionStatus">
<span ng-bind="project.ProjectName"></span>
<i class="fa fa-gear i-setup" ng-switch-when="1"></i>
<div ng-switch-when="0" ng-switch="project.CollectionStatus">
<i class="fa fa-star i-setup" ng-switch-when="1" ng-click="updateCol(0)"></i>
<i class="fa fa-star-o i-setup" ng-switch-when="0" ng-click="updateCol(1)"></i>
</div>
</div>
</div>
</div>
And here is the updateCol function:
$scope.updateCol = function(collectionStatus){
if (1 === collectionStatus) {
console.log("marked");
//$(this).removeClass("fa fa-star-o i-setup ng-scope");
//$(this).addClass("fa fa-star i-setup ng-scope");
//do something to change its class from "fa-star-o" to "fa-star"
}
else if (0 === collectionStatus) {
console.log("unmarked");
//do something to change its class from "fa-star" to "fa-star-o"
}};
How to solve this? When I use id selector, all the classes are changed, not the one that I want to modify. Please help me.

in the click handler just update the value of CollectionStatus
<i class="fa fa-star i-setup" ng-switch-when="1" ng-click="project.CollectionStatus = 0"></i>
<i class="fa fa-star-o i-setup" ng-switch-when="0" ng-click="project.CollectionStatus = 1"></i>
Demo: Plunker
Using ng-class
<div class="panel-heading" ng-switch="project.PermissionStatus">
<span ng-bind="project.ProjectName"></span>
<i class="fa fa-gear i-setup" ng-switch-when="1"></i>
<i class="fa i-setup" ng-class="{'fa-star': project.CollectionStatus == 1, 'fa-star-o': project.CollectionStatus == 0 }" ng-click="updateStatus(project)"></i>
</div>
then
$scope.updateStatus = function(project){
project.CollectionStatus = project.CollectionStatus == 0 ? 1 : 0;
//do your ajax here
if (1 === project.CollectionStatus) {
console.log("marked");
//$(this).removeClass("fa fa-star-o i-setup ng-scope");
//$(this).addClass("fa fa-star i-setup ng-scope");
//do something to change its class from "fa-star-o" to "fa-star"
}
else if (0 === project.CollectionStatus) {
console.log("unmarked");
//do something to change its class from "fa-star" to "fa-star-o"
}
};
Demo: Plunker

1 === collectionStatus is not equal to true === collectionStatus, so you should use 1 == collectionStatus or simply collectionStatus
$scope.updateCol = function(collectionStatus){
if (collectionStatus) {
console.log("marked");
//$(this).removeClass("fa fa-star-o i-setup ng-scope");
//$(this).addClass("fa fa-star i-setup ng-scope");
//do something to change its class from "fa-star-o" to "fa-star"
}
else{
console.log("unmarked");
//do something to change its class from "fa-star" to "fa-star-o"
}};

Related

How to target all elements with Jquery on click

Only first element getting clicked not all, how to get alert on all elements.
Jsfiddle
var btn = document.querySelector(".box i");
btn.onclick = function () {
alert('hello');
}
<div class="box">
<i class="fa fa-address-book-o" aria-hidden="true"></i>
<i class="fa fa-address-book-o" aria-hidden="true"></i>
<i class="fa fa-address-book-o" aria-hidden="true"></i>
<i class="fa fa-address-book-o" aria-hidden="true"></i>
</div>
Try querySelectorAll for select all then attract onclick to all element
var btnlist = document.querySelectorAll(".box i");
btnlist.forEach(element =>{element.onclick = function () {
alert('hello');
}});
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<div class="box">
<i class="fa fa-address-book-o" aria-hidden="true"></i>
<i class="fa fa-address-book-o" aria-hidden="true"></i>
<i class="fa fa-address-book-o" aria-hidden="true"></i>
<i class="fa fa-address-book-o" aria-hidden="true"></i>
</div>
Despite the title of the question, you don't currently use jQuery in your code. So, I provide 2 solutions:
jQuery:
jQuery('.box i').click(function() {
alert('hello');
});
Pure JS
window.addEventListener('click', function(e) {
// or e.target.classList.contains('fa-address-book-o')
if (e.target.className === 'fa fa-address-book-o') { // Better to add some additional class to identify element, like "fireAlert" for instance.
alert('hello');
}
});
Alternatively, you could select icons with query selector and add individual event listeners to all of them in a loop, but it's bad for performance & generally not considered a good thing to do.
The reason why it only work on the first element is that using .querySelector() method will select only the first element the meet your selector criteria, to be able to select all the elements you have to use .querySelectorAll() which will return a NodeList which can iterate through like this:
var btns = document.querySelectorAll(".box i");
btns.forEach((el, i) => {
el.onclick = function () {
console.log(`Hello! ${i}`);
}
});
<div class="box">
<i class="fa fa-address-book-o" aria-hidden="true">1</i>
<i class="fa fa-address-book-o" aria-hidden="true">2</i>
<i class="fa fa-address-book-o" aria-hidden="true">4</i>
<i class="fa fa-address-book-o" aria-hidden="true">5</i>
</div>

Changing className after insertAdjacentHTML

I am trying to change my className after the insertAdjacentHTML() function. I am using an AJAX request for this and the route /reviewcombine is from my backend JavaScript codes.
My codes:
<html>
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<style>
.checked {
color: orange;
}
</style>
<script>
function getTestByID() {
var request = new XMLHttpRequest();
//The "/reviewcombine" here is the route from my backend JavaScript
request.open("GET", "/reviewcombine", true);
request.setRequestHeader("Content-Type", "application/json");
request.onload = function () {
var tests = JSON.parse(request.responseText);
var exampleID = 1
var totalTests = tests.length;
var testlistings = document.getElementById("testListings");
for (var testCount = 0; testCount < totalTests; testCount++) {
if (tests[testCount].reviewResId == exampleID) {
var username = tests[testCount].username;
var rating = tests[testCount].rating;
var testItem = '<div class="eachtest">\
<h5 style="padding:6px; background-color: #E1ECF4; display: inline-block">#'+ username + '</h5>\
<div style="margin-top: 1px; padding-left: 3px;">\
<p style="color: rgb(255, 136, 0); font-size: 16px; display: inline;">'+ rating + '</p> \
<span class="fa fa-star" id="test_1"></span>\
<span class="fa fa-star" id="test_2"></span>\
<span class="fa fa-star" id="test_3"></span>\
<span class="fa fa-star" id="test_4"></span>\
<span class="fa fa-star" id="test_5"></span>\
\
</div>\
</div>';
// insertAdjacentHTML() to insert the HTML codes.
testlistings.insertAdjacentHTML('beforeend', testItem);
//cant change after insertAdjacentHTML????????????????????
var star = tests[testCount].rating
if (star == 0) {
return;
}
else if (star == 1) {
document.getElementById('test_1').className = "fa fa-star checked"
}
else if (star == 2) {
document.getElementById('test_1').className = "fa fa-star checked"
document.getElementById('test_2').className = "fa fa-star checked"
}
else if (star == 3) {
document.getElementById('test_1').className = "fa fa-star checked"
document.getElementById('test_2').className = "fa fa-star checked"
document.getElementById('test_3').className = "fa fa-star checked"
}
else if (star == 4) {
document.getElementById('test_1').className = "fa fa-star checked"
document.getElementById('test_2').className = "fa fa-star checked"
document.getElementById('test_3').className = "fa fa-star checked"
document.getElementById('test_4').className = "fa fa-star checked"
}
else {
document.getElementById('test_1').className = "fa fa-star checked"
document.getElementById('test_2').className = "fa fa-star checked"
document.getElementById('test_3').className = "fa fa-star checked"
document.getElementById('test_4').className = "fa fa-star checked"
document.getElementById('test_5').className = "fa fa-star checked"
}
}
}
}
request.send();
}
</script>
</head>
<body onload="getTestByID()">
<div id="testListings"></div>
</body>
</html>
Here, I am trying to change my stars to orange and display it based on the ratings value.
However, doing this after the insertAdjacentHTML function just changes the classNames permanently. The subsequent loops are using the fa fa-star checked class instead of the fa fa-star class that they should be using. (Doing it before the insertAdjacentHTML function is also not possible)
This is an example of the output I am getting:
Can someone please help me to identify what is the error here? Any relevant sources would also be a big help. Thanks a lot!
Inside the loop you are assigning a hard-coded id:
<span class="fa fa-star" id="test_1"></span>
document.getElementById('test_1") is only going to return the first instance of it, because id is supposed to be unique. Try making the id dynamically.

How to change image on hover of multiple images

I have a list of images and I want to be changed when I hover on it and then change back to the previous image on mouse leave. and each image is different. I have done it but it's not the right way of doing it. and I couldn't figure out the right way.
//html code: its actually long list but I'm just showing two of the list//
<li>
<div class="card">
<img class="my-img" id="my-img1" src="./images/AMH010301_G-1-dresslink.jpg" alt="Denim Jeans"onmouseover="hover1()" onmouseout="offhover1()">
<h1>Lorem1</h1>
<span class="price-first">$24.99</span>
<span class="price">$17.99</span>
<br>
<span class="fa fa-star checked"></span>
<span class="fa fa-star checked"></span>
<span class="fa fa-star checked"></span>
<span class="fa fa-star"></span>
<span class="fa fa-star"></span>
<p>Lorem ipsum dolor sit amet..</p>
<button class="add-to">Add to Cart</button>
</div>
</li>
<li>
<div class="card">
<img class="my-img" id="my-img2" src="./images/AMH010327_W-1-dresslink.jpg" alt="Denim Jeans" onmouseover="hover2()" onmouseout="offhover3()">
<h1>Lorem2</h1>
<span class="price-first">$24.99</span>
<span class="price">$14.99</span>
<br>
<span class="fa fa-star checked"></span>
<span class="fa fa-star checked"></span>
<span class="fa fa-star checked"></span>
<span class="fa fa-star"></span>
<span class="fa fa-star"></span>
<p>Lorem ipsum dolor sit amet..</p>
<button class="add-to">Add to Cart</button>
</div>
</li>
//javascript code//
function hover1() {
document.getElementById("my-img1").src = "./images/AMH010301_G-5-dresslink.jpg";
}
function offhover1() {
document.getElementById("my-img1").src = "./images/AMH010301_G-1-dresslink.jpg";
}
function hover2() {
document.getElementById("my-img2").src = "./images/AMH010327_W-5-dresslink.jpg";
}
function offhover2() {
document.getElementById("my-img2").src = "./images/AMH010327_W-1-dresslink.jpg";
}
function hover3() {
document.getElementById("my-img3").src = "./images/AMH011122_W-3-dresslink.jpg";
}
function offhover3() {
document.getElementById("my-img3").src = "./images/AMH011122_W-1-dresslink.jpg";
}
function hover4() {
document.getElementById("my-img4").src = "./images/AMH011200_W-3-dresslink.jpg";
}
function offhover4() {
document.getElementById("my-img4").src = "./images/AMH011200_W-2-dresslink.jpg";
}
Although what you've done works fine, the code looks a bit messier. The solution for a clean, well-organized code would be like this. First, you should consider that you can use a single javascript function to handle all 8 events since they belong to a related logical group. for example, you should have used a javascript function and use the e event param to identify the event triggered and then use a switch or any other suitable control structure to handle the events from different UI elements.
NOTE: another approach that I would recommend is using jquery library. Because it is optimized for this type of things.
Here's how I would do something like this with event listeners and a really simple swapping function. You could also do this with CSS which may be optimal depending on your case.
window.onload = function bindEvents(){
var img1 = document.querySelector('#my-img1');
img1.addEventListener('mouseover', function(){swapImage(img1, "./images/AMH010301_G-5-dresslink.jpg")});
img1.addEventListener('mouseout', function(){swapImage(img1, "./images/AMH010301_G-1-dresslink.jpg")});
}
function swapImage(el, elImg) {
el.src = elImg;
}

color icons upto the hover position

I have 10 circles (Fontawesome icons) horizontally placed. I want to fill colors to them when the user hover on any icon. For ex: if the user hovers on the 5th circle, all the circles upto the 5th circle should fill in color. (Something like in a rating system) How can i do it?
Following is the code which i render 10 circles.
export const RatePersonalityCard = ({}) => {
for (let score = 1; score < 11; score++) {
let scoreList = [];
scoreList.push(
<div className="trait_vote_single tooltip" style={{fontSize:'40px',color:'gray'}} onClick={() => handleClick(score)}>
{/*<div className="trait_vote_circle"></div>*/}
<i className="fa fa-circle-thin" aria-hidden="true"></i>
<a className="trait_value" style={{marginTop:'-34px',marginLeft:'-1px'}}>{score}</a>
<span className="tooltiptext2 unchange_div" style={{marginLeft: '-40px'}}>{starvalue}</span>
</div>
)
}
return (
<div className="">
<div className="single_trait_rate width_100 text_align_center">{userTraits.trait_name}</div>
<div className="trait_vote_div">
{scoreList}
</div>
</div>
);
};
You could create a hover event for each for every score list item that adds a class to the currently hovered item and everything prior. Then add a blur event to every item to remove the class.
function handleHover(e) {
let index = scoreList.indexOf(e.target);
for (let i = 0; i <= index; i++) {
scoreList[index].classList.add('highlight');
}
}
function handleBlur(e) {
scoreList.forEach(function(item) {
item.classList.remove('highlight');
});
}
No CSS example. I don't see great value in adding any JS to something that can simply done via CSS. If you also need a click event, it's as simple as 1 class on 1 span. I'd also recommend reading:
Decoupling Your HTML, CSS, and JavaScrip which my code does not do.
span .fa-star{
display: none;
}
span:hover > .fa-star{
color: yellow;
display: inline-block;
color: red;
}
span:hover > .fa-star-o{
display: none;
}
span { cursor: pointer }
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<span>
<i class="fa fa-star-o" aria-hidden="true"></i>
<i class="fa fa-star" aria-hidden="true"></i>
<span>
<i class="fa fa-star-o" aria-hidden="true"></i>
<i class="fa fa-star" aria-hidden="true"></i>
<span>
<i class="fa fa-star-o" aria-hidden="true"></i>
<i class="fa fa-star" aria-hidden="true"></i>
<span>
<i class="fa fa-star-o" aria-hidden="true"></i>
<i class="fa fa-star" aria-hidden="true"></i>
<span>
<i class="fa fa-star-o" aria-hidden="true"></i>
<i class="fa fa-star" aria-hidden="true"></i>
</span>
</span>
</span>
</span>
</span>

jquery/javascript play/stop asynchronous issue

I have a page that is essentially dynamically created (this is key), and in this page I have divs, and each div is supposed to play/pause a song.
The code works if I put alert, so that led me to believe that there is an asynchronous issue. So I tried to add a timeout to when I call play/pause, but that didn't work either.
How the code behaves right now is the first div functions flawlessly, but any other div does not work unless I put an alert.
Has anyone had experience with such an issue?
This is my code, I'm using livequery to pick up the dynamic elements.
EDIT:
The problem now is that only the first song is being played, nothing happens when I click play/pause buttons for the other songs.
function callAction(url) {
if (url == "music.html") {
var believe = new Audio('/assets/music/believe.mp3');
var hope = new Audio('/assets/music/hope.mp3');
var alf = new Audio('/assets/music/alf.mp3');
var thatnight = new Audio('/assets/music/thatnight.mp3');
var lostlove = new Audio('/assets/music/lostlove.mp3');
var time = new Audio('/assets/music/time.mp3');
$("body").on("click", ".pausebutton", function(){
var song = $(this).attr('name');
if (song != null && song == "believe") {
believe.pause();
}
if (song != null && song == "hope") {
hope.pause();
}
if (song != null && song == "alf") {
alf.pause();
}
if (song != null && song == "thatnight") {
thatnight.pause();
}
if (song != null && song == "lostlove") {
lostlove.pause();
}
if (song != null && song == "time") {
time.pause();
}
});
$("body").on("click", ".playbutton" ,function(){
var song = $(this).attr('name');
if (song != null && song == "believe") {
believe.play();
}
if (song != null && song == "hope") {
hope.play();
}
if (song != null && song == "alf") {
alf.play();
}
if (song != null && song == "thatnight") {
thatnight.play();
}
if (song != null && song == "lostlove") {
lostlove.play();
}
if (song != null && song == "time") {
time.play();
}
});
}
}
Not that html would really make a difference, but here is the html:
<div id="music">
<h1>Music</h1>
<br><br>
<div class="row">
<div class="musicEntry red">
<center><p class="musicTitle">Believe</p></center>
<center><p class="musicDate">July 27th 2014</p></center>
<div class="audio-controls">
<center><i name="believe" class="fa fa-play-circle fa-3x playbutton"></i></center>
<center><i name="believe" class="fa fa-pause fa-3x pausebutton"></i></center>
</div>
</div>
<div class="musicEntry red">
<center><p class="musicTitle">A Little Hope</p></center>
<center><p class="musicDate">March 8th 2014</p></center>
<div class="audio-controls">
<center><i name="hope" class="fa fa-play-circle fa-3x playbutton"></i></center>
<center><i name="hope" class="fa fa-pause fa-3x pausebutton"></i></center>
</div>
</div>
<div class="musicEntry red">
<center><p class="musicTitle">Alf Layla</p></center>
<center><p class="musicDate">April 23rd 2014</p></center>
<div class="audio-controls">
<center><i name="alf" class="fa fa-play-circle fa-3x playbutton"></i></center>
<center><i name="alf" class="fa fa-pause fa-3x pausebutton"></i></center>
</div>
</div>
</div>
<div class="row">
<div class="musicEntry red">
<center><p class="musicTitle">That Night</p></center>
<center><p class="musicDate">March 21th 2013</p></center>
<div class="audio-controls">
<center><i name="thatnight" class="fa fa-play-circle fa-3x playbutton"></i></center>
<center><i name="thatnight" class="fa fa-pause fa-3x pausebutton"></i></center>
</div>
</div>
<div class="musicEntry red">
<center><p class="musicTitle">Lost Love</p></center>
<center><p class="musicDate">July 30th 2012</p></center>
<div class="audio-controls">
<center><i name="lostlove" class="fa fa-play-circle fa-3x playbutton"></i></center>
<center><i name="lostlove" class="fa fa-pause fa-3x pausebutton"></i></center>
</div>
</div>
<div class="musicEntry red">
<center><p class="musicTitle">Time (Cover)</p></center>
<center><p class="musicDate">July 26th 2012</p></center>
<div class="audio-controls">
<center><i name="time" class="fa fa-play-circle fa-3x playbutton"></i></center>
<center><i name="time" class="fa fa-pause fa-3x pausebutton"></i></center>
</div>
</div>
</div>
</div>
This is only playing and pausing the first song. Do you have any idea why?
The issue is your click event and dynamically loaded page. When there are dynamically added elements on your DOM, use $(selector).on('click', function(e){}) instead of click events. Below is the modified handler:
$(".playbutton").on("click", function(){
// Your code goes here
});
Have a look at this jsfiddle
http://jsfiddle.net/cVjg9/1/
If you use the method Inder described in the JSFiddle it doesn't work either. For some reason you have to attach it like this:
$("#container").on("click",".pausebutton",function(e){...});
The first selector can be any containing element, for example $("body").
Thinking about it...
The explanation is most likely because you're attaching the event to the top element, not the dynamic element. Every time you click on the surrounding container, the event will be caught and a check will be done whether you clicked on a ".pausebutton" sub-element. In other words, it's more performant to use a dedicated div which closely encapsulated the dynamically loaded elements, instead of just attaching it to the body. Otherwise it will throw events all over the place.
Attaching events like this doesn't work:
$(".pausebutton").on("click",function(e){...});
http://jsfiddle.net/J2LYX/
$(".pausebutton").click(function(e){...});
http://jsfiddle.net/X2rbJ/
Related question:
In jQuery, how to attach events to dynamic html elements?
I solved some of the problem by taking livequery out.
While I am getting my dynamic content using $.get(url), I made a function that acts as a switch. So something like this:
//Get the page here
$.get(url, function() {
//replace content of the page here
callAction(url);
});
// This acts as a switch statement, the javascript is being called just fine, and the code works perfectly now.
function callAction(url) {
if (url == "music.php"){
// do the following here
}
if (url == "blog.php"){
// do the following here
}
}
This worked for me. I didn't have to use livequery anymore. That plugin is terrible.

Categories

Resources