VueJs not removing image after second button is clicked - javascript

So I'm trying to make a team comparison on my web app to compare their stats, the problem is that after I selected two teams then remove either one of the team, at first I succeed but when I try to remove the last one its doing nothing the last team logo is still showing up. Below is my code.
On the console it shows that selectedTeams values are undefined after remove-first and remove-second are clicked
undefined (2) [undefined, "TeamB", __ob__: Observer] 0
undefined (2) [undefined, undefined, __ob__: Observer] 1
Display Team Logo
<div class="col-md-6 first-selected">
<img id="firstteamlogo" :src="selectedTeams[0] | spacetodash | useLGLogo" v-if="selectedTeams[0] || selectedTeams[0] != undefined">
</div>
<div class="col-md-6 second-selected">
<img id="secondteamlogo" :src="selectedTeams[1] | spacetodash | useLGLogo" v-if="selectedTeams[1] || selectedTeams[1] != undefined">
</div>
Remove Team Logo
<div class="add-area">
<i class="fa fa-times remove-first" aria-hidden="true" v-if="selectedTeams[0]" v-on:click="removeTeams"></i>
<i class="fa fa-plus select-first" aria-hidden="true" v-else></i>
<span v-if="selectedTeams[0]">vs</span>
<span v-else>Comparison</span>
<i class="fa fa-times remove-second" aria-hidden="true" v-if="selectedTeams[1]" v-on:click="removeTeams"></i>
<i class="fa fa-plus select-second" aria-hidden="true" v-else></i>
</div>
Team Selection
<div class="team-selection" v-if="showTeamSelection">
<div class="team-row">
<div class="col-md-3" v-for="(team, index) in teams" v-if="index < 4">
<div class="team-logo">
<img class="team" :src="team.clubName | spacetodash | useMDLogo" :id="team.clubName | removespace" :data-team-name="team.clubName" :data-team-id="team.teamId" v-on:click="selectTeams">
</div>
</div>
</div>
<div class="team-row">
<div class="col-md-3" v-for="(team, index) in teams" v-if="index > 3">
<div class="team-logo">
<img class="team" :src="team.clubName | spacetodash | useMDLogo" :id="team.clubName | removespace" :data-team-name="team.clubName" :data-team-id="team.teamId" v-on:click="selectTeams">
</div>
</div>
</div>
</div>
VueJs Code
export default {
data: function(){
return {
teams: {},
isTeamsSelected: true,
isPlayersSelected: false,
showTeamSelection: true,
selectedTeams: [],
selectedPlayers: [],
}
},
mixins: [
filters,
methods
],
methods: {
selectTeams(e) {
if(this.selectedTeams.length < 2){
this.selectedTeams.push(e.target.dataset.teamName);
if(this.selectedTeams.length == 2){
this.showTeamSelection = false;
}
console.log(this.selectedTeams);
}
return false;
},
removeTeams(e) {
let removeTeam = e.target.classList.value;
this.showTeamSelection = true;
if(removeTeam.indexOf('remove-first') >= 0){
this.selectedTeams[0] = undefined;
console.log(this.selectedTeams[0], this.selectedTeams, 0);
}
if(removeTeam.indexOf('remove-second') >= 0){
this.selectedTeams[1] = undefined;
console.log(this.selectedTeams[1], this.selectedTeams, 1);
}
},
},
mounted: function() {
let self = this;
this.getCurrentSeasonTeams().then(function(response){
if( response.status == 200 && response.data.length > 0 ) {
self.teams = response.data;
}
});
}
}

Just pass the team you want to remove.
<i class="fa fa-times" aria-hidden="true" v-if="selectedTeams[0]" v-on:click="removeTeams(selectedTeams[0])"></i>
And change your removeTeam method.
removeTeams(team) {
this.selectedTeams.splice(this.selectedTeams.indexOf(team), 1)
this.showTeamSelection = true;
}

Related

Click listener to update count

The below is part of a media player. Unfortunately, I cannot find the reason why the event listener is not registering the clicks on the hearts (when a user favorites a song). I have tried several implementations and I am researching for the last week with no success. Can you help?
How can I make the click listener to update the heart count?
HTML
<div class="player">
<div class="dashboard">
<header>
<p>Playing:</p>
</header>
<div class="cd">
<div class="cd-thumb">
</div>
</div>
<div class="control">
<div class="btn btn-random inactive">
<i class="fas fa-random"></i>
</div>
<div class="btn btn-prev">
<i class="fas fa-step-backward"></i>
</div>
<div class="btn btn-toggle-play">
<i class="fas fa-pause icon-pause"></i>
<i class="fas fa-play icon-play"></i>
</div>
<div class="btn btn-next">
<i class="fas fa-step-forward"></i>
</div>
<div class="btn btn-mute-unmute inactive">
<i class="fas fa-volume-up"></i>
</div>
</div>
</div>
<div class="playlist">
</div>
Script 1
render: function () {
let that = this;
fetch("hearts.txt")
.then(function(response) {
return response.json();
})
.then(function(heartCounts) {
let t = that.songs.map(
(t, e) => `
<div class="song ${
e === that.currentIndex ? "active" : ""
}" data-index="${e}">
<div class="thumb"
style="background-image: url('${t.image}')">
</div>
<div class="body">
<h3 class="title">${t.name}</h3>
<p class="author">${t.singer}</p>
</div>
<div class="heart" data-song-id="${e}">
<i class="fa fa-heart${
heartCounts[e] ? " active" : ""
}"></i> <span>${heartCounts[e] || 0}</span>
</div>
</div>
`
);
playlist.innerHTML = t.join("");
});
},
Script 2
const getHeartCounts = function () {
let xhr = new XMLHttpRequest();
xhr.open("GET", "return.php", true);
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
let heartCounts = JSON.parse(xhr.responseText);
// Update the heart count displays
document.querySelectorAll(".heart i + span").forEach((countDisplay, i) => {
countDisplay.innerHTML = heartCounts[i];
});
// Update the active heart icons
document.querySelectorAll(".heart i").forEach((heart, i) => {
if (heartCounts[i] > 0) {
heart.classList.add("active");
}
});
}
};
xhr.send();
};
document.addEventListener("DOMContentLoaded", function () {
// Add click listener to update the heart count
document.querySelectorAll(".heart").forEach(function (heart) {
heart.addEventListener("click", function (e) {
let target = e.target,
songIndex = parseInt(target.dataset.songId),
countEl = target.querySelector("span"),
heartCount = countEl ? parseInt(countEl.innerHTML) : 0,
isActive = target.classList.contains("active");
// Update the heart count
heartCount = isActive ? heartCount - 1 : heartCount + 1;
if (countEl) {
countEl.innerHTML = heartCount;
}
let heartIcon = target.querySelector("i");
if (heartIcon) {
heartIcon.classList.toggle("active", !isActive);
}
// Update the heart count on the server
let xhr = new XMLHttpRequest();
xhr.open("POST", "store.php", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send("index=" + songIndex + "&count=" + heartCount);
});
});
// Update the heart counts on page load
getHeartCounts();
});

Angular 6 timer issue

I have a view which polls an endpoint every 30 seconds and updates if there are changes. In the same view I have a div which is shown/hidden every 7 seconds. The timers are started at the same time.
The first few times it runs, it runs perfectly. It's not until the first 30s timer polls again that it basically starts flickering back and forward every 2 seconds - which it shouldn't.
component.ts
getScreen(tapCode) {
timer(0, 30000)
.pipe(mergeMap(() => this.dataService.get_screen(tapCode)))
.subscribe(objectResp => {
this.callResp = objectResp.status;
this.polledObj = objectResp.items;
this.landing = false;
this.loaded = true;
this.unavailable = objectResp.items.unavailable;
localStorage.setItem('ontapCode', tapCode);
this.getAds(this.polledObj);
});
}
getAds(polledObj) {
this.showAd = false;
this.adTimer = timer(0, 7000);
this.adSubscription = this.adTimer.subscribe(() => {
if(this.timerCount >= this.polledObj.adverts.length) {
this.timerCount = 0;
}
if(this.timerCount <= this.polledObj.adverts.length) {
this.adImage = this.polledObj.adverts[this.timerCount].filename;
this.timerCount++;
}
this.showAd = !this.showAd;
});
}
component.html
<div *ngIf="callResp === 'OK'" class="tap">
<div *ngIf="unavailable === '1' || unavailable === 1" class="object-unavailable">
<img src="./assets/unavailable.png" class="unavailable-img">
</div>
<div *ngIf="unavailable === '0' || unavailable === 0">
<img src={{polledObj.img}} class="img-object">
<div class="container">
<div *ngIf="showAd === true">
<div class="advertisement">
<img src={{adImage}}" class="img-ad">
</div>
</div>
<div *ngIf="showAd === false">
<div class="object-detail-container">
<h3 (click)="resetStorage()" class="object-name text-white">{{polledObj.object_name}}</h3>
<h4 class="text-white object-brewery">{{polledObj.brewery}}</h4>
<h4 class="text-white object-style">{{polledObj.style}} - {{polledObj.abv}}%</h4>
<div class="object-sizes" *ngFor="let size of polledObj.sizes">
<span class="object-size-name">{{size.name}}: </span>
<span class="object-size-volume"> {{size.volume*1000}}ml </span>
<span class="object-size-price"> ${{getPrice(size.price)}} </span>
<span class="object-size-std"> {{getSizeStd(size)}} </span>
<span class="object-size-std-drinks"> std drinks</span>
</div>
</div>
</div>
</div>
</div>

Typing in a input text is very slow using angular 4

When I type in text to search something, displaying one character in text is very slow.
What is the problem ?
I have display 50 products with ngFor as below , if I display more than 50 products 100 or 150 typing in text is more slow.
what should I do to fix this problem ?
<div class="width_products products-animation " *ngFor="let product of productsService.products ; trackBy: $index" [ngClass]="{ 'width_products_open_menu':productsService.status_menu }" >
<span class="each_width_product" >
<div class="title_products more_detail_product" (click)="set_router({ path:product['company'].company_name+'/'+product.product_title , data:product.product_id , relative:true })">
{{product.product_title }}
<span class="glyphicon glyphicon-chevron-down"></span><br>
<div class=' glyphicon glyphicon-time'></div> {{product.product_date}}
</div>
<div class="image_product_primary " (click)="set_router({ path:product['company'].company_name+'/'+product.product_title , data:product.product_id , relative:true })">
<img class="image_product" src="../../assets/images/products_image/{{product.product_image}}">
</div>
<button (click)="product.product_in_wishList='true'; productsService.add_wish_list( product )" mat-button class="wish_list notCloseDropdawnFavorite notCloseDropdawnCard">
<span class="write_add_wish">{{dataservices.language.add_wishlist}}</span>
<mat-icon *ngIf="product.product_in_wishList == 'false' " class="notCloseDropdawnFavorite notCloseDropdawnCard">favorite_border</mat-icon>
<mat-icon *ngIf="product.product_in_wishList == 'true' " class="hearts_div_hover notCloseDropdawnFavorite notCloseDropdawnCard">favorite</mat-icon>
</button>
<div class="footer_products">
<span matTooltip="Views!">
<div class="button_footer_products">
<span class="glyphicon glyphicon-eye-open icon_eye"></span>
<div class="both_write ">
12889
</div>
</div>
</span>
<span matTooltip="Add to your card" class="notCloseDropdawnCard notCloseDropdawnFavorite " (click)="product.product_in_cartList='true'; productsService.add_cart_list( product )">
<div class="button_footer_products">
<span *ngIf="product.product_in_cartList=='false'" class="glyphicon glyphicon-plus icon_eye notCloseDropdawnCard notCloseDropdawnFavorite" ></span>
<span *ngIf="product.product_in_cartList=='true'" class="glyphicon glyphicon-ok icon_eye notCloseDropdawnCard notCloseDropdawnFavorite" ></span>
<div class="both_write ">
Cart
</div>
</div>
</span>
<span matTooltip="See Details!">
<div (click)="set_router({ path:product['company'].company_name+'/'+product.product_title , data:product.product_id , relative:true })" class="button_footer_products" >
<span class=" glyphicon glyphicon-option-horizontal icon_eye"></span>
<div class="both_write ">
More
</div>
</div>
</span>
</div>
<div class="prise_products">
Price:<del>$2500</del> $3500
</div>
<div class="plus_height"></div>
</span>
</div>
In header component I have a input type text as below :
<input type="text" class="kerkim" name="search" [(ngModel)]="typing_search" placeholder="
{{dataservices.language.searchproducts}}">
Debouce effect, e.g. do not run search immediately.
class Coponent {
private _timeoutId: number;
//to be called on search text changed
search(){
clearTimeout(this._timeoutId);
this._timeoutId = setTimeout(() => {
//do search stuff
}, 500) //play with delay
}
}
Cache prev results using search keyword.
When kyeword changes like so ["k","ke","key"] you do not need to refilter whole array.
class Search {
private _keywordChanges:string[] = [];
private _prevFilterResults: any[] = [];
private _allData: any[] = [];
search(keyword:string){
let prevKeyword = this.getPrevKeyword(),
toBeFiltered: any[];
if(keyword.match(keyword)){ //if it was "ke" and now it is "key"
//filter prev results only
toBeFiltered = this._prevFilterResults;
} else {
//filter prev results or even make cache for keyword
toBeFiltered = this._allData;
}
let results = toBeFiltered.filter(() => {});
this._prevFilterResults = results;
}
private getPrevKeyword(){
return this._keywordChanges[this._keywordChanges.length - 1];
}
Use for with break instead of Array.filter(), in some cases it may be helpfull. For example you have sorted array ["a","apple","b","banana"] and keyword "a".
function search(array:any[], keyword:string) {
//so
let results = [];
for(let i = 0; i < array.length; i++){
let item = array[i];
if(item.toString().startsWith(keyword)){
results.push(item);
} else {
break; //as b and banana left
}
}
return results;
}
Take a look at binary search. How to implement binary search in JavaScript
and hash table Hash table runtime complexity (insert, search and delete)
From my issue: every input field is slow due to many data. so i add "changeDetection: ChangeDetectionStrategy.OnPush" at where data reloaded, then everything work normal.
#Component({
selector: 'app-app-item',
templateUrl: './app-item.component.html',
styleUrls: ['./app-item.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
})

I can´t remove the last item of array

I can remove any item of array unless the last one. I also use angularjs to show information in the view. I don´t know what is happening with the last item of this array. Please, anyone can help me?
Here is HTML:
<div class="row">
<div class="col-md-12">
<h4><strong>Documento {{index + 1}} de {{documentos.length}}:</strong> {{documentos[index].nome}}</h4>
<iframe style="background: #ccc;" ng-show="exibirPreview" frameborder="0" ng-src="{{versaoLink}}" width="100%" height="300px"></iframe>
<div class="alert alert-warning" ng-hide="exibirPreview">
#Html.Raw(Resources.Dialog.SignDocuments.TypeDocumentCanNotPreDisplayed)
</div>
<hr />
<div class="pull-right btn-row" ng-show="documentos.length > 1">
<button class="btn btn-default" type="button" ng-click="RemoveDoc(index)"><i class="fa fa-fw fa-times"></i> #Resources.Common.RemoveDocList</button>
</div>
</div>
</div>
Here is js/angularjs
$scope.documentos = [
{nome:"document1", chave: "8F65579E3737706F", extensao:".pdf"},
{nome:"document2", chave: "8F65579E3730007F", extensao:".pdf"},
{nome:"document3", chave: "8545579E3737706F", extensao:".pdf"},
{nome:"document4", chave: "8555579E3730007F", extensao:".pdf"}
]
$scope.ViewLink = function () {
var versao = $scope.documentos[$scope.index];
$scope.exibirPreview = versao.extensao == ".pdf" || versao.extensao == ".txt";
if (!$scope.exibirPreview) {
$scope.versaoLink = '';
} else {
$scope.versaoLink = '/Documento/VersaoView?chave=' + versao.chave;
}
};
$scope.ViewLink();
$scope.RemoveDoc = function (index) {
$scope.documentos.splice(index, 1);
$scope.ViewLink();
};
Or Plunker
In your HTML you are preventing the deletion of the last element:
<div class="pull-right btn-row" ng-show="documentos.length > 1">
<!-- -->
</div>
documentos.length > 1 means "hide when it reaches one item in the array".
It should be documentos.length == 0.
It's either this or your index value starts from 1 and not from 0.
The simplest solution would be to change your remove function to take in the document instead of the index. Try this:
$scope.RemoveDoc = function(document) {
var index = $scope.documents.indexOf(document);
$scope.documents.splice(index, 1);
}
in view:
<button class="btn" type="button" ng-click="RemoveDoc(document)">Delete</button>

How to trigger ng-hide on all elements

I have a list that when you click on an li, it reveals a hidden list of information about that person.
In the footer, theres simple navigation showing the different views and when you click, angular filters through the original list for the matched elements.
All I am stuck on is this;
if you click an li element and reveal the info for that person, then click one of the navigation buttons, it will still show that person but with the hidden element revealed...not closed.
Ideally, id prefer that when the user clicks any of the footer navigation buttons, the list reveals just the names, not the hidden info..regardless of whether it was clicked or not.
If this was just in Jquery or javascript, i would know how to approach this but, Im sure theres an 'angular specific' approach I just don't know about.
Heres the HTML:
<div ng-controller="MyCtrl">
<ul id="housewrapper" ng-cloak>
<li ng-repeat="item in house track by item.member" class="listings" ng-click="showComments = !showComments;" ng-show="([item] | filter:filters).length > 0" >
<span ng-if="item.whereHesheStands == 'oppose'"><img class="dot againstdot" src="img/against.png">{{item.member}}
</span>
<span ng-if="item.whereHesheStands == 'leanoppose'">
<img class="dot againstdot" src="img/against.png">{{item.member}}
</span>
<span ng-if="item.whereHesheStands == 'support'" ng-click="clickMeImg($event);">
<img class="dot supportdot" src="img/support.png">{{item.member}}
</span>
<span ng-if="item.whereHesheStands == 'leansupport' ">
<img class="dot supportdot" src="img/support.png">{{item.member}}
</span>
<span ng-if="item.whereHesheStands == 'unknown' ">
<img class="dot undecideddot" src="img/undecided.png">{{item.member}}
</span>
<span ng-if="item.whereHesheStands == 'undecided' ">
<img class="dot undecideddot" src="img/undecided.png">{{item.member}}
</span>
<div class="memberdetail" ng-show="showComments" ng-click="$event.stopPropagation();" >
<ul class="memberbreakdown">
<li class="partyline" >
{{item.party}} - {{item.state}}</li>
<li class="comments">
<span style="color:#a4a4a4;" ng-if="!(item.comments)">Comment not available</span>
<span>{{item.comments}}</span>
</li>
</ul>
</div>
</li>
</ul>
<div id="appfooterWrapper">
<ul id="appfooter">
<li ng-click="myFunctionRepublican();" ng-class="class">R</li>
<li ng-click="myFunctionDemocrat();" ng-class="class2">D</li>
<li ng-click="myFunctionSupport();" ng-class="class3">S</li>
<li ng-click="myFunctionOppose();" ng-class="class4">A</li>
<li ng-click="myFunctionUnknown();" ng-class="class5">U</li>
</ul>
</div>
and the javascript of the "R" navigation button
$scope.myFunctionRepublican = function() {
$('.memberdetail').removeClass('ng-show');
$('.memberdetail').bind('click');
$scope.filters = function(house) {
return house.party == 'R' ;
};
if ($scope.class === ""){
$scope.class = "rep";
$scope.class2 = "";
$scope.class3 = "";
$scope.class4 = "";
$scope.class5 = "";
}
else{
$scope.class = "";
}
$('html, body').animate({scrollTop:0}, 'fast');
var loading;
loading = true;
if (loading == true) {
setTimeout(function() {
spinner.stop();
$('.listings').not('.ng-hide').addClass('republican');
console.log($('.republican').length);
$('#housewrapper').stop().fadeIn(350).addClass(
'marginAdd');
$('#subhead').removeClass('slidedown');
$('#subhead').html('Republicans').css('color', '#d41600');
setTimeout(function() {
$('#subhead').addClass('slidedown');
}, 300);
}, 500);
}
}
Here's the Fiddle
A couple changes, attach a property onto each member.
View changes:
ng-click="item.showComments = !item.showComments;"
<div class="memberdetail" ng-show="item.showComments" ng-click="$event.stopPropagation();" >
Controller changes:
function resetShow() {
for(var i = 0, l = $scope.house.length; i < l; i++) {
$scope.house[i].showComments = false;
}
}
Then just call it when you navigate:
$scope.myFunctionUnknown = function() {
resetShow();
....
Forked Fiddle

Categories

Resources