ng click update model not resetting ng src - angularjs

I have a ng repeat which will display four images.
On click on any one of these, I have to change the image of the particular one and reset other to its previous image. My angularJs code goes like this
<div class='col-lg-3 col-md-3 col-xs-6 col-sm-6 noPaddingLeftRight' ng-repeat="category in categoryList">
<img ng-click="selectedCategory = category.Category_Id; selectedNo = category.RunningNumber;" ng-src="{{$index == selectedNo?category.HoverImageName:category.CategoryImage}}" alt='home' style='align-content: center; margin-top: 10px;' />
</div>
after I click it will change the particular one but it won't reset the previous image.
What I am doing wrong?

You're making way harder than necessary. Why do you need two variables to remember which category is selected? Why do you set the selectedNo to category.RunningNumber, but then comparing it with $index. If it's supposed to be an index, then set it to the index. If it's supposed to be the running number of the category, then compare it with the runing number.
Also, you're modifying a variable of the scope, but ng-repeat has its own scope. So each iteration has its own selectedCategory and selectedNo.
So, create an object in your controller:
$scope.model = {
selectedCategory: null
};
And then all you need is
<div ng-repeat="category in categoryList">
<img ng-click="model.selectedCategory = category"
ng-src="{{ model.selectedCategory == category ? category.HoverImageName : category.CategoryImage }}" />
</div>
Or delegate to a function:
$scope.selectedCategory = null;
$scope.selectCategory = function(category) {
$scope.selectedCategory = category;
};
<div ng-repeat="category in categoryList">
<img ng-click="selectCategory(category)"
ng-src="{{ selectedCategory == category ? category.HoverImageName : category.CategoryImage }}" />
</div>

Related

How to bind a part of a variable already binded

I have a loop ng-repeat that displays sevral icons.
<div class="box">
<div class="box-body">
<div class="row" >
<div class="col-sm-6" style="margin-bottom: 5px;" ng-repeat="record in newlayout.display" align="center">
<a class="btn btn-app" ng-href="#newlayout/{{newlayout.url}}{{newlayout.itemValue}}" >
<span class="badge bg-yellow" style="font-size:22px;">{{record.numberOfSamples}}</span>
<i class="fa fa-{{newlayout.labStyle}}"></i> {{record.lab}}
</a>
</div>
</div>
</div>
</div>
My issue is that the second part of the binded variable itemValue should be dynamic
In my Js, I have this
newLayout.url = 'sublabs/?labName=';
newLayout.itemValue = 'record.lab';
The URL is dynamic.
When I click on the first displayed Icon, the url should look like this :
But it didn't work as I had a compilation error..
Does someone have an idea how to fix this:
http://localhost:8181/#/newlayout/sublabs?labName=PIA/C1 - Shiftlabo
Where the record value "PIA/C1 - Shiftlabo" change.
So basically here if I change
<a class="btn btn-app" ng-href="#newlayout/{{newlayout.url}}{{newlayout.itemValue}}" >
{{newlayout.itemValue}} by {{record.lab}} it would work..but the {{record.**lab**}} should be dynamic as it will have another value when I click on the icon. It will change to {{record.subLab}}
Thanks
Use property acccessor bracket notation inside the binding:
<div>{{record[labOrSublab]}}</div>
JS
var isSublab = false;
$scope.labOrSublab = "lab";
$scope.clickHandler = function() {
isSublab = !isSublab;
$scope.labOrSublab = isSublab ? 'subLab' : 'lab';
};

AngularJS filter is requiring two clicks before it filters results

I am a beginner at angular. I am pretty certain I am doing this the completely incorrect way but because I finally have it "somewhat working" as it works on the second click I am stuck going in this direction and can't seem to figure out another way to do it.
The filter sorts on the second click because it is initialing as "undefined" before the first click and sets it based on that I believe.
In my html:
<div class="col-xs-12 col-sm-4 location-list" ng-repeat="key in careerlist.location">
<div class="locations" ng-click="careerlist.criteriaMatch()">{{key}}
</div>
</div>
<div class="col-xs-12">
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-4 job-container" ng-repeat="job in careerlist.career | filter : searchText | filter: selectExperience | filter: careerlist.criteria.name">
<h2>
{{job.title}}
</h2>
<h3>
{{job.location}}
</h3>
<div class="job-description" ng-bind-html="job.description | limitHtml : 200">
</div>
<br><br>
<button>Read More</button>
</div>
<br><br>
</div>
</div>
In my controller:
cl.criteriaMatch = function( criteria ) {
jQuery(document).on('click', '.locations', function(){
cl.criteria = {};
console.log("just the element text " + jQuery(this).text());
cl.criteria.name = jQuery(this).text();
return function( criteria ) {
return criteria.name === criteria.name;
};
});
};
Use ng-click instead of jQuery#on('click'). Angular does not know that the filter should be updated.
Update
#Makoto points out that the click is bound twice. It very much looks like you should just remove the jQuery binding altogether. I would even go so far as suggesting removing jQuery from you project.

ng-show if filter and inner if statements are valid

I have an ng-repeat being created like so:
<div class="items">
<!-- WANT TO HIDE THIS ENTIRE AREA IF THERE IS NO VALID ITEMS -->
<b>Items</b>
<span ng-repeat="item in items | orderBy:'priority'" itemid="{{item.$id}}" ng-if="!item.groupID || item.groupID == 'misc'">
{{item.title}}
</span>
</div>
As you can see I have an ng-if which checks if the item has a null item.groupid or is in the misc category.
Many times there is no items that match all of these criteria and in that case I want to hide the outer div <div class="items">
I can't figure out how to hide it because I can't do an ng-show on the inner elements part of the loop.
You can use a filter, and assign the result of the filter to a variable. Use that variable to decide if the enclosing div should be shown or not.
Here's a plunkr showing how it works:
<div ng-show="filteredItems.length > 0">
Test
<div ng-repeat="item in items | filter:hasGroupFilter(group) as filteredItems">
{{ item.name }} - {{ item.group }}
</div>
</div>
And in the controller:
$scope.hasGroupFilter = function(group) {
return function(item) {
return !item.group || item.group === group;
};
};
I think the cleanest way to do that is to pre filter the list, and add a condition on your parent div.items instead of using ng-if in each one of the span in the ng-repeat.
Here is a working plunker
You should filter the list in your controller and just add the condition on the parent div
<div class="items" ng-if="filteredItems.length">
<b>Items</b>
<span ng-repeat="item in filteredItems | orderBy:'priority'" itemid="{{item.$id}}">
{{item.title}}
</span>
</div>
You could potentially create a function that has access to a public variable on the outer scope. It would look something along the lines of this:
Inside your JS file
$scope.NoValidItems = true; //assume no valid items code also might look different based on how you format your angular
$scope.CheckItems = function(item){
var check = false;
if(item.groupID && item.groupID !== 'misc'){
check = true;
$scope.NoValidItems = false;
}else
check = false;
return check;
};
HTML
<div class="items" ng-if="!NoValidItems ">
<!-- WANT TO HIDE THIS ENTIRE AREA IF THERE IS NO VALID ITEMS -->
<b>Items</b>
<span ng-repeat="item in items | orderBy:'priority'" itemid="{{item.$id}}" ng-if="!CheckItems(item)">
{{item.title}}
</span>
</div>
This should work, and the if statement might not be exact, but you get the drift. Pretty much if there is one that is valid it will show, but if there is not a valid item do not show. Valid being meeting your conditional criteria. Hopefully this helps, and I explained it alright

How to bind array with ng-bind-html directive in angularJS?

I want to show for every item different description.
This is the controller:
todoApp.controller('todos',function($scope,todoFactory){
todoFactory.getTodos().success(function (data) {
courses = x2js.xml_str2json(data);
$scope.todos = courses.rss.channel.item;
for(var i = 0 ; i < $scope.todos.length ; i++){
item = $scope.todos[i];
console.log(item.description);
$scope.message = item.description;
}
});
this is the html:
<div ng-controller="todos" class="list" style="padding-top: 8%">
<div class="list card" ng-repeat="todo in todos | filter:search" >
<div class="item item-avatar" ng-click="openLink(todo.link)" >
<img src="Bla-Bla-Logo-1.png">
<h2>{{todo.title}}</h2>
<p>{{todo.pubDate | limitTo:25 }}</p>
</div>
<div class="item item-body">
<p ng-bind-html="message"></p>
<p>
1 Like
5 Comments
</p>
</div>
</div>
<!--end list card-->
</div>
<!--end todos-->
Just to explain the code I get xml and convert into json so todos is array of objects.
Message is entering every object and get the description (but in the description has tags so i use ng-bind-html directive to show it properly).
I understand that $scope.message will hold just the last description. How to make it to belong in the ng-repeat so I can get different description for different item?
Thanks.
replace
<p ng-bind-html="message"></p>
with
<p ng-bind-html="todo.description"></p>
please provide the data which is you want to displayed repeatedly.
How data is represented.You are getting last one because it is overriding.
The "ngBind" attribute tells Angular to replace the text content of the specified HTML element with the value of a given expression, and to update the text content when the value of that expression changes.
Typically, you don't use "ngBind" directly, but instead you use the double curly markup like {{ expression }} which is similar but less verbose.

Why am I getting "Error: 'undefined' is not a function (evaluating 'items.split(',')')" here?

I'm getting the following error while typing into the field filtered by 'completeList'. Why is this happening?
JavaScript
angular.module('myApp', ['timer'])
.controller('AppCtrl',['$scope', function($scope){
$scope.gameOn = true;
$scope.leaders = true;
$scope.myScore = true;
}])
.filter('completeList', function() {
return function(items) {
var list = [];
if(items) {
list = items.split(',');
var last = list[list.length - 1];
if(items.charAt(items.length - 1) != ',' || last.length === 0)
list.pop();
}
return list;
};
});
HTML
<div ng-show="gameOn" ng-controller="LabelCtrl" class="row marketing">
<div class="col-lg-4">
<h4>Enter comma-separated labels for this image</h4>
<form role="form" class="form-inline" >
<input ng-list ng-model="labels" placeholder="Enter labels" class="form-control" type="text" >
<button class="form-control" class="btn btn-xs btn-success">Submit</button>
</form>
</div>
<div class="col-lg-2">
<h4>Labels</h4>
<div>
<ol>
<li ng-repeat="label in labels track by $index | completeList">
{{ label }}
</li>
</ol>
</div>
</div>
The good news is that you only have a minor Angular syntax error. It is actually mentioned in the documentation:
Filters should be applied to the expression, before specifying a
tracking expression.
...
For example: 'item in items | filter:searchText track by item.id' is a pattern that might be used to apply a filter to items in conjunction with a tracking expression.
Given this knowledge, just change your ngRepeat line to the following, it does work exactly as you intended and works perfectly on my side:
<li ng-repeat="label in labels | completeList track by $index">
I do not know what the data structure of labels so here is my best stab at it. Filters are applied onto the instance of your iteration of your loop. It looks like you may be trying to apply the filter to the entire collection instead of that index of the loop. The filter is applied to label not labels. In this case you cannot split it. Again I dont know your data structure so I am kind of guessing here. It would be helpful if you could reveal what labels is.
Thanks,
Jordan

Resources