How to trigger ng-hide on all elements - javascript

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

Related

JavaScript works until one of the options is choosen

I have a page that sorts things if you choose one of the options. The list of filters was too long so I added a div that shows/hides options. On page load some of the options are hidden via CSS with display: hidden. Code below just changes display from display: none to display: inline-block based on number of clicks.
var timesClicked = 0;
window.onload = function(){
document.getElementById("filter_attribute_217").onclick = function(){
timesClicked++;
if (timesClicked%2==0){
hide();
} else {
show();
}
};
This is show() function
function show(){
document.getElementById("filter_attribute_69").style.display="inline-block";
document.getElementById("filter_attribute_70").style.display="inline-block";
document.getElementById("filter_attribute_72").style.display="inline-block";
//all those other options
document.getElementById("filter_attribute_217").innerHTML = "less";
document.getElementById("filter_attribute_217").style.borderTop = "1px dashed #e1e4e6";
document.getElementById("filter_attribute_68").style.borderBottom = "none";
document.getElementById("filter_attribute_87").style.borderBottom = "none";
}
And this is hide() function
function hide(){
document.getElementById("filter_attribute_217").innerHTML = "more";
document.getElementById("filter_attribute_217").style.borderTop = "1px dashed #e1e4e6"
document.getElementById("filter_attribute_69").style.display="none";
document.getElementById("filter_attribute_70").style.display="none";
//all those other options
document.getElementById("filter_attribute_103").style.display="none";
}
This is working perfectly until I choose one of the options which means that some other disappear. Then when trying to use more/less button I will get errors like this one:
Uncaught TypeError: Cannot read properties of null (reading 'style')
at hide (user.js?sci=481:68:50)
at document.getElementById.onclick (user.js?sci=481:58:9)
Clicking it again shows the same error just with show() function.
I've tried checking if element exist in DOM structure with document.body.contains(YOUR_ELEMENT_HERE); but it always shows that all of the options exists. Checked it with
if(document.body.contains(element){
console.log("exists")
} else {
console.log("doesn't exist")
}
Console was always outputting "exists".
I then tried just ignoring the problem to see if others options will show with
function stoperror() {
return true;
};
window.onerror = stoperror;
But with the same result just without the error. I don't know why this is happening and how can I fix it. I need to add that all I can edit here is JavaScript and CSS. That's why I made another option (filter_attribute_217) and made it into my show more/less button.
Edit
Here's HTML code for basically every option. They only thing that is changing from option to option is id and href.
<div data-limit="3" class="group group-filter" id="filter_attribute_104">
<h5>
Transparent
</h5>
<ul>
<li class="" style="margin-right:15px;">
<a title="tak" href="/pl/c/Balls/119/1/default/1/f_at_104_0/1">
<i src="/libraries/images/1px.gif" alt="" class="px1" ></i>
<span>tak </span>
<em>(56)</em>
</a>
</li>
</ul>
<div data-limit="3" class="group group-filter" id="filter_attribute_68">
<h5>
White
</h5>
<ul>
<li class="" style="margin-right:15px;">
<a title="tak" href="/pl/c/Balls/119/1/default/1/f_at_68_0/1">
<i src="/libraries/images/1px.gif" alt="" class="px1" ></i>
<span>tak </span>
<em>(208)</em>
</a>
</li>
</ul>
I also have this in my JS code
window.addEventListener("DOMContentLoaded",(event) => {
document.getElementById("filter_attribute_217").innerHTML = "więcej";
document.getElementById("filter_attribute_217").style.borderTop = "1px dashed #e1e4e6";
});
This is an example with the code you provided. However your question is still not properly stated. I assume the HTML is getting generated dynamically? If so, I would make sure that the elements I'm trying to use are existing for sure while I call my JS. So I got rid of the window.onload you are using. Also, if you want to apply global changes, do not repeat the same things for each ID, just use a querySelectorAll('.classname') with a .forEach. Example:
let timesClicked = 0;
let show = () => {
document.querySelector('.group-filter').innerHTML = 'LESS';
document.querySelectorAll('.group-filter').forEach(elem => {
elem.style.display = 'flex';
// Other things...
});
}
let hide = () => {
document.querySelector('.group-filter').innerHTML = 'MORE';
document.querySelectorAll('.group-filter').forEach(elem => {
elem.style.display = 'none';
// Other things...
});
// Restore the first element's display
document.querySelector('.group-filter').style.display = 'flex';
}
document.getElementById('filter_attribute_104').addEventListener('click', () => {
timesClicked++;
if (timesClicked % 2 == 0) hide();
else show();
});
.hidden {display:none;}
<div data-limit="3" class="group group-filter" id="filter_attribute_104">
<h5>Transparent</h5>
<ul>
<li class="" style="margin-right:15px;">
<a title="tak" href="#">
<i src="/libraries/images/1px.gif" alt="" class="px1" ></i>
<span>tak </span>
<em>(56)</em>
</a>
</li>
</ul>
</div>
<div data-limit="3" class="group group-filter hidden" id="filter_attribute_68">
<h5>White</h5>
<ul>
<li class="" style="margin-right:15px;">
<a title="tak" href="#">
<i src="/libraries/images/1px.gif" alt="" class="px1" ></i>
<span>tak </span>
<em>(208)</em>
</a>
</li>
</ul>
</div>
<div data-limit="3" class="group group-filter hidden" id="filter_attribute_168">
<h5>Red</h5>
<ul>
<li class="" style="margin-right:15px;">
<a title="tak" href="#">
<i src="/libraries/images/1px.gif" alt="" class="px1" ></i>
<span>tak </span>
<em>(332)</em>
</a>
</li>
</ul>
</div>

set all ng-if to false on click except clicked item

I have an ng-repeat which has a button that has a function that toggles an ng-show element inside that ng-repeat.
The inside the class movie_option span has an ng-click=toggleInfo($index):
And the div additional_info has an ng-show that shows or hides an element.
<ul ng-cloak="showResult">
<li class="search_results" ng-repeat="movie in movies | orderBy: '-release_date' track by $index">
<div class="movie_info">
<div class="movie_options">
<div class="slide">
<span class="movie_option">
<span><i class="fa fa-question-circle" aria-hidden="true" ng-click="toggleInfo($index)"></i></span>
</span>
</div>
</div>
</div>
<div class="additional_info" ng-show="hiddenDiv[$index]">
{{movie.overview}}
</div>
</li>
</ul>
When a user clicks on the icon it calls this function:
$scope.toggleInfo = function (index) {
$scope.hiddenDiv[index] = !$scope.hiddenDiv[index];
}
This toggles the ng-show state from the hiddenDiv ng-show. This works fine.
What I wanted to do is put all hiddenDiv states on false except the one that is clicked so only one ng-show would be true.
That's a pure algorithm problem, not related to Angular.
Instead of having a boolean per item, it would be much simpler to just remember the element (index) that should be displayed:
<ul ng-cloak="showResult">
<li class="search_results" ng-repeat="movie in movies | orderBy: '-release_date' track by $index">
<div class="movie_info">
<div class="movie_options">
<div class="slide">
<span class="movie_option">
<span><i class="fa fa-question-circle" aria-hidden="true" ng-click="model.displayedIndex = $index"></i></span>
</span>
</div>
</div>
</div>
<div class="additional_info" ng-show="$index === model.displayedIndex">
{{movie.overview}}
</div>
</li>
</ul>
And in your controller $scope.model = {}
Fiddle: http://jsfiddle.net/6dkLqgfL/
I think this would do:
$scope.toggleInfo = function(index) {
for(var i in $scope.hiddenDiv) {
if(index != i)
$scope.hiddenDiv[i] = false;
}
$scope.hiddenDiv[index] = !$scope.hiddenDiv[index];
}
You could just manually turn all the hiddenDiv elements to false when the toggleInfo function is fired.
$scope.toggleInfo = function(index){
for(int i = 0; i<($scope.hiddenDiv).length; i++)
$scope.hiddenDiv[i] = false;
$scope.hiddenDiv[index] = !$scope.hiddenDiv[index];
}
See if this works?

Bind paired data in object to another element outside ng-repeat - angular

I have this array of objects that I need to work with:
$scope.pdfs = [
{ "pdf_title": "Corporate Hire", "attached_file": "http://file1.jpg"},
{ "pdf_title": "Wedding Hire", "attached_file": "http://file2.jpg"},
{ "pdf_title": "Filming Hire", "attached_file": "http://file3.jpg"}
];
The pdf_file value is ng-repeated in li's.
What I want to do is if that li is clicked, to push its paired to another div, say the src for an href.
Here are my workings, but not quite correct:
Controller function:
$scope.bindWithFile = function(value) {
var currentValue = $scope.corpResult = value;
// pdfs support
var pdfs = $scope.pdfs;
for (var i = pdfs.length - 1; i >= 0; i--) {
if (currentValue == hasOwnProperty(key[pdfs])) {
value[pdfs] = $scope.corpLinkHref;
}
};
Markup:
<div class="w-12" ng-controller="corpHireController">
<div class="c-6-set">
<ul>
<li ng-repeat="pdf in pdfs" class="col-7 link link-inherit" ng-click="bindWithFile(pdf.pdf_title)">{{::pdf.pdf_title}}</li>
</ul>
</div>
<div class="c-6-set">
<div class="w-12">
<i class="fs-4 col-7 icon icon-pdf"></i>
</div>
<span class="col-7 h4" ng-bind="corpResult"></span>
<button ng-href="{{::corpLinkHref}}" class="button green2-button smaller-letters full-width">Download</button>
</div>
</div>
What is needed:
Clicking on the titles on the left, binds the pdf_title under the pdf icon and binds the attached_file to the button's href
Instead of passing the title of the selected pdf, why not passing the whole object. This way you don't have to performance any find or search function.
Markup:
<div class="w-12" ng-controller="corpHireController">
<div class="c-6-set">
<ul>
<li ng-repeat="pdf in pdfs" class="col-7 link link-inherit"
ng-click="bindWithFile(pdf)">
{{::pdf.pdf_title}}
</li>
</ul>
</div>
<div class="c-6-set">
<div class="w-12">
<i class="fs-4 col-7 icon icon-pdf"></i>
</div>
<span class="col-7 h4" ng-bind="corpResult"></span>
<button ng-href="{{::corpLinkHref}}"
class="button green2-button smaller-letters full-width">
Download
</button>
</div>
</div>
Controller
$scope.bindWithFile = function(selectedPdf) {
$scope.corpResult = selectedPdf.pdf_title;
$scope.corpLinkHref = selectedPdf.attached_file;
}

AngularJS only showing one list item at a time

HTML
<ul class="column__list">
<li class="column__list--item" ng-repeat="task in tasks | orderBy:'name':false" data-ng-class="{active:taskIndex=={{$index}}}">
<div class="column__list--expand fa" ng-click="expand = !expand" ng-class="{'fa-chevron-down': !expand, 'fa-chevron-up': expand}"></div>
<div class="column__list--actions slide" ng-show="expand">
{{ children }}
</div>
</li>
</ul>
ANGULAR
angular.module('App.animate', [])
.animation('.slide', function() {
var NgHideClassName = 'ng-hide';
return {
beforeAddClass: function(element, className, done) {
if(className === NgHideClassName) {
jQuery(element).slideUp(done);
console.log('0');
}
},
removeClass: function(element, className, done) {
if(className === NgHideClassName) {
jQuery(element).hide().slideDown(done);
console.log('1');
}
}
}
});
I have the above which when clicked a div will slideDown and when clicked again will slideUp .column__list--expand
This works but what if I only wanted to have one li on show at a time and also update the ng-class too?
jsFiddle example
Change your template to:
<div ng-app="testApp" ng-controller="testController">
<ul class="column__list">
<li class="column__list--item" ng-repeat="task in tasks | orderBy:'name':false" data-ng-class="{active:taskIndex=={{$index}}}">
<div class="column__list--expand fa" ng-click="$parent.selectedTask = $parent.selectedTask == task ? null : task" ng-class="{'fa-chevron-down': $parent.selectedTask!=task, 'fa-chevron-up': $parent.selectedTask==task}">{{ task.title }}</div>
<div class="column__list--actions slide" ng-show="$parent.selectedTask==task">
{{ task.description }}
</div>
</li>
</ul>
</div>
jsfiddle solution

Keep track of tabs with knockoutjs + twitter bootstrap

I'm trying to keep track of the selected tab in the view model but I can't seem to make it work.
In the following code when you click a tab the header will update correctly but the content of the tab is not displayed. If you remove , click: $parent.selectSection then the contents are shown but the header does not update.
Now if you remove the data-bind="css: { active: selected }" from the li then it seems to work when you click the tabs but the button to select the second tab doesn't.
How can I make this work?
See: http://jsfiddle.net/5PgE2/3/
HTML:
<h3>
<span>Selected: </span>
<span data-bind="text: selectedSection().name" />
</h3>
<div class="tabbable">
<ul class="nav nav-tabs" data-bind="foreach: sections">
<li data-bind="css: { active: selected }">
<a data-bind="attr: { href: '#tab' + name }
, click: $parent.selectSection" data-toggle="tab">
<span data-bind="text: name" />
</a>
</li>
</ul>
<div class="tab-content" data-bind="foreach: sections">
<div class="tab-pane" data-bind="attr: { id: 'tab' + name }">
<span data-bind="text: 'In section: ' + name" />
</div>
</div>
</div>
<button data-bind="click: selectTwo">Select tab Two</button>
JS:
var Section = function (name) {
this.name = name;
this.selected = ko.observable(false);
}
var ViewModel = function () {
var self = this;
self.sections = ko.observableArray([new Section('One'),
new Section('Two'),
new Section('Three')]);
self.selectedSection = ko.observable(new Section(''));
self.selectSection = function (s) {
self.selectedSection().selected(false);
self.selectedSection(s);
self.selectedSection().selected(true);
}
self.selectTwo = function() { self.selectSection(self.sections()[1]); }
}
ko.applyBindings(new ViewModel());
There are several ways that you can handle this either using bootstrap's JS or by just having Knockout add/remove the active class.
To do this just with Knockout, here is one solution where the Section itself has a computed to determine if it is currently selected.
var Section = function (name, selected) {
this.name = name;
this.isSelected = ko.computed(function() {
return this === selected();
}, this);
}
var ViewModel = function () {
var self = this;
self.selectedSection = ko.observable();
self.sections = ko.observableArray([
new Section('One', self.selectedSection),
new Section('Two', self.selectedSection),
new Section('Three', self.selectedSection)
]);
//inialize to the first section
self.selectedSection(self.sections()[0]);
}
ko.applyBindings(new ViewModel());
Markup would look like:
<div class="tabbable">
<ul class="nav nav-tabs" data-bind="foreach: sections">
<li data-bind="css: { active: isSelected }">
<a href="#" data-bind="click: $parent.selectedSection">
<span data-bind="text: name" />
</a>
</li>
</ul>
<div class="tab-content" data-bind="foreach: sections">
<div class="tab-pane" data-bind="css: { active: isSelected }">
<span data-bind="text: 'In section: ' + name" />
</div>
</div>
</div>
Sample here: http://jsfiddle.net/rniemeyer/cGMTV/
There are a number of variations that you could use, but I think that this is a simple approach.
Here is a tweak where the active tab used the section name as a template: http://jsfiddle.net/rniemeyer/wbtvM/

Categories

Resources