Angular ng-show multiple conditions (no more than 3 work) - javascript

I have a div which I need to show when any of 5 conditions are true.
The problem is that ng-show seems to take into consideration only the first 3 conditions. I don't know if it's only my problem, cause I couldn't find any related problem.
In the following example I kept moving conditions around, but each time only the first 3 conditions are taken into consideration. Whatever condition falls into the 4th position, does not show the div.
Please let me know if you know a work around in case it's not possible to have more than 3 conditions.
It's a pretty big div, so I post only a part:
<div class="row " ng-show="selectedAllP[0] || selectedAllF[0] || selectedAllP || selectedAllD || level">
<div class="row selectedCase">
<div><h3 id="choices">Your choices:</h3></div>
<div class="col-md-4" id="publisher">
<h4>Publishers</h4>
<div class="level" ng-hide="selectedAllP[0] || selectedAllP">Select publisher</div>
<table class="table table-bordered table-striped">
<tbody id="pub">
<tr ng-hide="selectedAllP.Name === ' - Any Publisher -'" ng-repeat="roll in selectedAllP" ng-click="deSelectP(roll)">
<td class="deselect">{{roll.Name}}</td>
</tr>
<tr ng-show="selectedAllP.Name === ' - Any Publisher -'" ng-click="deSelectP(selectedAllP)">
<td class="deselect">{{selectedAllP.Name}}</td>
</tr>
</tbody>
</table>
<p ng-show="noticeAnyPublisher && selectedAllP.Name === ' - Any Publisher -'" class="notice">{{noticeAnyPublisher}}</p>
</div>
And the logic for a part of the div above:
$scope.selectedAllP = [];
$scope.setSelectedP = function (publisher) {
$scope.selectedP = publisher.Name;
// Check if the selected publisher is already in the array
// if it isn't, than push it in the array (else do nothing)
if (publisher.Name == " - Any Publisher -"){
$scope.selectedAllP = publisher;
console.log($scope.selectedAllP);
} else if ($scope.selectedAllP.Name == " - Any Publisher -") {
$scope.noticeAnyPublisher = 'Deselect "Any Publisher" first';
console.log("blblblb");
} else if ($scope.selectedAllP.indexOf(publisher) == -1) {
$scope.selectedAllP.push(publisher);
}
console.log($scope.selectedP, $scope.selectedAllP);
};
$scope.deSelectP = function (dePublisher) {
// Check if the selected publisher is already in the array
// if it is, than remove it from the array (else do nothing)
if (dePublisher.Name == " - Any Publisher -") {
$scope.selectedAllP = [];
$scope.selectedP = 0;
$scope.noticeAnyPublisher = '';
} else {
var idx = $scope.selectedAllP.indexOf(dePublisher);
if (idx != -1) {
$scope.selectedAllP.splice(idx, 1);
$scope.selectedP = $scope.selectedAllP[0].Name;
}
}
};
I want when I choose the 4th condition (in this case || selectedAllD) to show the div above, but as u can see, even if the distributor is selected (and selectedAllD exists in console), the div doesn't show. Check next image to see the div showing when I select the 3rd condition (selectedAllF[0]).
div showing when I select the 3rd condition (selectedAllF[0]). It is showing for the fisrt 2 conditions too. Problem is that its behavior is the same, whatever the order of the conditions (it only considers the first 3 conditions).

You could call a method in your ng-show.
<div class="row " ng-show="showRow()">
and declare that function into your .js file.
$scope.showRow = function () {
return $scope.selectedAllP[0] || $scope.selectedAllF[0] || $scope.selectedAllP || $scope.selectedAllD || $scope.level;
}

No matter how many condition you will pass to ng-show or any ohter directive which accepts expressions. See this docs Angular Expressions. So instead, check all of the parts of you condition statement. In such representation it will be evaluated to true every time when there is AT LEAST 1 statement which returns true. Also it is worth to note that this expression will be evaluated from left to right and UNTIL first true statement will be found.

Related

How do I create a better control for rendering custom vue elements?

I have a survey, that people can take. However, if you are one of the first 1000 to fill out the survey you are given a reimbursement. What I am struggling with is how to only show the reimbursement when the users are less than 1000.
The questions in the survey are coming from a CMS backend, while the reimbursement is built on the front end.
<div class="questionContainer" v-if="intentGiven && consentGiven && !surveyComplete">
<div v-if="$store.state.scoring.gameCompleted && this.index == this.QuestionnaireSize && this.ParticipantCount <= 1000">
<ResearchQuestionReimbursement v-on:answered="advanceQuestion"/>
</div>
<div v-else>
<ResearchQuestionMultipleChoice :question="questions[index]"
v-if="questions[index].Type == 'MultipleChoice'"
v-on:answered="advanceQuestion" />
<ResearchQuestionFreeAnswer :question="questions[index]"
v-if="questions[index].Type == 'FreeAnswer'"
v-on:answered="advanceQuestion" />
</div>
</div>
questions[index] is an array of the questions received from the backend CMS. The reimbursement is only supposed to be at the end which is why I have the div wrapped around <ResearchQuestionReimbursement>.
My control logic for the index is:
if (this.index < this.questions.length -1 || (this.$store.state.scoring.gameCompleted && this.index < this.questions.length)) {
this.index++;
console.log(`post: ${this.index}`)
} else {
.....
//required code to save the form
}
Currently, if I have over 1000 users the logic continues and gives me an index undefined error. This makes sense since the index would be 13 and the array would only be 12. I have tried a v-if on <ResearchQuestionReimbursement> to check if there are 1000 users. This resulted in a blank page rendering since it rendered the div but not the content.
What it should do is if there are more than 1000 users it will skip to the else statement.

How to do a Pug for loop with AJAX?

I am working on a Tinder clone web project for school using Node.js, Express, and Pug that needs to return potential matches with a priority on either distance from the current user or similar interests shared with the current user. When the user first enters their page of potential matches I have the site automatically show the user the best possible matches based on a distance of 5km from their current position. I am sending to the page I render an Array of matches called users and a size of that array called userslen that I pulled from my database in my node file. I then proceed to show the potential matches on the page using this pug for loop:
div(class='container', id='searchResults') <!-- SEARCH RESULTS -->
div(class='row')
- for (var i = 0; i < userslen; i++) {
div(class='col-lg-4 col-md-6 col-sm-12 col-xs-12 usertop')
div(class='row')
div(class='col-lg-12 col-md-12')
a(href='/users/' + users[i].username)
h1=users[i].username
- if (users[i].liked == true) {
span(id='youlikeglyph', class="glyphicon glyphicon-ok")
- } else if (users[i].disliked == true) {
span(id='youdislikeglyph', class="glyphicon glyphicon-remove")
- } else {
- }
div(class='row')
div(class='col-lg-12 col-md-12')
img(id='viewerphoto1', class='userpagephoto', src='/static/uploads/' + users[i].filename)
div(class='row')
- if (users[i].liked == false && users[i].disliked == false) {
div(class='btn-group')
button(id='dislike' + i, class='btn btn-danger btn-lg')
|Dislike
button(id='like' + i, class='btn btn-success btn-lg')
| Like
- } else if (users[i].liked == false && users[i].disliked == true) {
button(id='like' + i, class='btn btn-success btn-lg')
|Like
- } else if (users[i].liked == true && users[i].disliked == false) {
button(id='dislike' + i, class='btn btn-danger btn-lg')
|Dislike
- } else {
- }
div(class='row')
div(class='col-lg-4 col-md-4')
h5="Distance"
h4=users[i].distance + "km"
div(class='col-lg-4 col-md-4')
h5="Same Tags"
h4=users[i].cTags
div(class='col-lg-4 col-md-4')
h5="Popularity"
h4=users[i].popularity
- }
There are two buttons at the top of my page (not shown in the above code) that allow a user to choose to search based on distance or based on tags with a min and max distance/tags-in-common input. When they click on the button of their choice with the min max they have entered I send the data through AJAX to a post that then returns a new array of potential matches based on this new data. Is there a way to make the same for loop I have in the above code but using jQuery once my AJAX response is a success? If there is, what is the best way to go about it? Thank you in advance for your help!
You cannot go back to Jade/Pug once you're on the client. Jade is a templating engine that works on Node. Once you're on the client, it doesn't exist anymore.
You'll need to just loop over your HTML in jQuery, and won't be able to use Jade for this.
Another option is to use one of the client side templating frameworks like Underscore templates/Handlebars/Moustache JS etc.
Using these, you can handle the looping much more elegantly than you can using jQuery, but of course, that really is a call you should take, because this would mean additional payload over the wire.
With one of the templating frameworks, you can define your template in Jade and then reuse it for your iterations

Creating Angular Element Once

I have an angular page that displays a list of items. It iterates over the list and displays it in a div. Here's the HTML code for that:
<div ng-repeat="item in items">
<div class="item-title-section">
<h1>{{item.text}}</h1>
</div>
<div class="item-special-section"
ng-show="item.type == 'FooB' ||
item.type == 'FooC' ||
item.type == 'FooD'">
<div>
<h2>Speical</h2>
<p>Type Section</p>
</div>
<div>
<span>{{item.text}}</span>
</div>
</div>
</div>
The item-title-section always shows. But I only want the item-special-section to show if the current item is of type B, C, or D. The problem here is if the list contains all 3 items I just want the div to be printed once but the text of each item printed. So in this case:
{
{
type: FooA,
title: FooA,
text: "Some text for this element"
},
{
type: FooB,
title: FooB,
text: "Some text for this element"
},
{
type: FooC,
title: FooC,
text: "Some text for this element"
}
}
The item-special-section div prints twice. Is there a way in angular to statically create an html element, meaning if it's created create it only once?
So one workaround I have figured out for your problem is to allocate the logic for showing only one special item to a separate function attached to the $scope. I have created a Plnkr Example to help demonstrate my explanation.
HTML
<div class="item-special-section"
ng-show="showSpecialSection(item.type)">
<p>I'm a special case!</p>
<p>{{item.text}}</p>
</div>
In the HTML we only allow that element to show if showSpecialSection returns true and we pass in the item.type.
JavaScript
// Define out specialItems
$scope.specialItems = ['FooB', 'FooC', 'FooE'];
// Create an array to stash the first item that fulfills
// the requirement in showSpecialSection
$scope.allowedItem = [];
$scope.showSpecialSection = function(item) {
// First we check if the item is in our defined list
// of special items
if ($scope.specialItems.indexOf(item) != -1) {
// Next depending on if allowedItem has anything,
// we either add it to allowedItem or check if it is
// already inside allowedItem
if ($scope.allowedItem.length == 0) {
$scope.allowedItem.push(item);
return true;
}
else if ($scope.allowedItem.indexOf(item) != -1) {
return true;
}
}
// return false if all other logic checks failed
return false;
}
Please let me know if this works out for you, and comment if you have questions. Cheers ~

Increment inside angular expression

I am trying to show some divs (which are under 3+ ng-repeats) conditionally and then increment a counter variable which. The counter contributes in the conditions which decide the visibility of divs.
When I do something similar tong-show='foo++ < SOME_LIMIT' I get a syntax error:
Error: Syntax Error: Token 'undefined' not a primary expression at column NaN of the expression [moveItem.type != 'account' && team.rowCount++] starting at [moveItem.type != 'account' && team.rowCount++].
or
Error: Syntax Error: Token '2' is an unexpected token at column 42 of the expression [team.expandAccounts || team.rowCount++ < 2] starting at [2]
Giving the code doesn't seem to be required but still I am giving what I was trying.
I tried something similar to:
<div ng-repeat='request in pagedRequests'
<tr ng-repeat='(fooId, foo) in returnFoos(request)'>
<td ng-init='foo.rowCount = 0'>
{{foo.someAttribute}}
<!--Here is just an icon shown when the rowCount reaches some limit, say 3.
Uses ng-switch on foo.rowCount. Skipping this as this doesn't seem
problematic. This toggles rows' collapsing using foo.expandRows.-->
<div ng-repeat='bar in foo.bars'
ng-show='foo.rowCount < 3 || foo.expandRows'>
<span ng-show='bar.type=="multiRowBar"'
ng-repeat='row in bar.rows'>
<span ng-show="foo.expandRows || foo.rowCount++ < 3"> <!--SYNTAX ERROR!-->
<!--Showing the nested objects with more ng-repeats.-->
</span>
<span ng-show='bar.type!="multiRowBar" && foo.rowCount++<3'> <!--SYNTAX ERROR!-->
<!-- This adds a single row per bar of this type.-->
</span>
</div>
</td>
</tr>
</div>
Is it that we can't use post/pre increment/decrement operators (like ++) inside angular expressions?
Why just do not use method like:
<button ng-show='increaseFoo() < SOME_LIMIT'>press me</button>
controller
$scope.SOME_LIMIT = 10;
$scope.foo = 8;
$scope.increaseFoo = function(){
return $scope.foo++;
};
Fiddle
if $scope.foo = 8;, ng-show returns true
if $scope.foo = 9;, ng-show returns false
The question is a bit ignorant to the fact that such an effort triggers cyclic $digest calls which breaks. (Just for the sake of making some sense out of this question I'm giving my solution. Hope it will help someone trying this stuff) The solution I finalized involved flattening all the lists to a single list and switching to show the icon for a particular value of $index.

split a big HTML page to pages on client side

I have a huge HTML page which is mainly a form which is mostly like this:
<FIELDSET id= '1'>
<TABLE>
<TR> </TR>
</FIELDSET>
</TABLE>
.
.
.
<FIELDSET id= 'n'>
<TABLE>
<TR> </TR>
</TABLE>
The number of fieldsets are generated by dynamically on the server.
Question: On the client side I want to do a pagination for this huge page, so that only say,3 fieldset appear per page on the client.
I don't want to change the way page is loading or form is being submitted currently.
Well just a little tips you may use
$('fieldset')
document.querySelectorAll('fieldset')
will return you fields
in order to get show only i .. i+3 fieldsets you can use
var i = 3
$('fieldset').hide().each(function ( index, el) {
if (index >= i && index < i+3) $(el).show()
})
var fieldsets = [].slice(document.querySelectorAll('fieldset'))
for (var index in fieldsets) {
var display = index < i && index >= i+3 ? 'none' : ''
fieldsets[index].style.display = display
}
Pagination won't really help you in any way other than visual if done on the client side (no speed increases, load reductions, etc), but if that's what you want you can do it with DOM manipulation. Something like the following might work for you:
var i=0,sets=document.getElementsByTagName('fieldset'),len=sets.length;
for(;i<len;i+=3) {
// wrap sets[i] through sets[i+2], as long as they exist, in a div
// if i !== 0, hide or minimize the div
}
// add controls to unhide/unminimize each div

Categories