Evaluation not working in ng-show() - javascript

I am trying to put a checkmark icon next to some text in a <li> tag within an ng-repeat loop.
HTML
<ul>
<li ng-repeat="nav in tabs.nav">
{{nav.name}}
<i class="fa fa-check my-checked-icon"
ng-show="$index===selectedIndex"
ng-click="selectNav(nav.index)"></i>
</li>
</ul>
JS
$scope.tabs = {
"navs":[
{
"name":"Lorem Ipsum",
"index":0
},
{
"name":"Adipiscing Elit",
"index":1
},
{
"name":"Ut Lbore et Dolore",
"index":2
}
]
};
var selectedIndex = 1;
$scope.selectNav = function(index){
$scope.selectedIndex = index;
};
CSS
.my-checked-icon{
display: none;
}
Both $index and selectedIndex print out the correct values when I put them in {{}}. And I've tried doing no braces as well as evaluating with ==.
I get the error
Error: [$parse:lexerr] Lexer Error: Unexpected next character at columns 0-0 [“] in expression [“$index==selectedIndex"].
I've seen other examples of people evaluating like this elsewhere. What is the problem? Is there a better way to do this inside of the controller somehow?

Try this
HTML
<ul>
<li ng-repeat="nav in tabs.navs" ng-click="selectNav(nav.index)">
{{nav.name}}
<i class="fa fa-check my-checked-icon"
ng-show="$index===selectedIndex"
></i>
</li>
</ul>
JS
var ncolor;
$scope.tabs = {
"navs":[
{
"name":"Lorem Ipsum",
"index":0
},
{
"name":"Adipiscing Elit",
"index":1
},
{
"name":"Ut Lbore et Dolore",
"index":2
}
]
};
$scope.selectedIndex = 1;
$scope.selectNav = function(index){
$scope.selectedIndex = index;
};
There is nothing wrong in your validation. you were declaring selectedIndex as variable. you should define as a $scope variable. So only then you will see the check icon on the right. And I moved the ng-click to the so that when you click it the check mark will come beside that. If you click a check mark it will stay at the same place as the index always remains the same and you cannot click the checks which are hidden

Related

Hovering on one Value with class is affecting all the Values in the view Angular4?

<ul *ngFor="let item of workSpaceResponse; let i = index">
<li>
<span (mouseenter)='checkList(item.value, i)' title='{{info}}'>
<i [ngClass]="result ? 'fa fa-hourglass-end red' : 'fa fa-hourglass success'" aria-hidden="true"></i> Pass
</span>
</ul>
This is my Template, when I am hovering on one value , it is making same color, for all the list , dont know what i m doing wrong
result : boolean = false;
checkList(value){
r = passingMarks - value
if(r>1){
this.result = true;
}
What I want is, if there are passed students then show thier value with green and those who are fail, show them with red.
It's not very clear from your question what's going on, but I think you are having the 'bubbling' effect.
So change to
<span (mouseenter)='checkList($event,item.value, i)' title='{{info}}'>
and
checkList(event, value){
event.stopPropagation();
....
// as before
}

Deleting elements dynamically from ng-repeat generated list

I am having an array of json objects which have nested arrays. I am using ng-repeat to create list with those nested arrays. I want to delete the items from list dynamically on button click. I have written a function in controller to do that-
$scope.remove= function(path){
var obj = $scope.results[$scope.editIndex];
var i;
for(i = 0; i<path.length-1;i++){
var key = path[i].key;
var index = path[i].index;
if(!obj[key]) return;
obj = obj[key]
}
delete obj[path[i].key][path[i].index];
}
and calling it like-
<ul ng-show="showFeatures">
<li ng-repeat="(featureIndex,feature) in result.features">
<span ng-bind="feature" contenteditable={{result.edit}}></span>
<i class="flr-always material-icons pointer" ng-show="result.edit" ng-click="remove([{key:'features',index:featureIndex}])">delete</i>
</li>
</ul>
Problem is that I can not delete more than one element, as after first element indexes will change in array, but ng-repeat does not changes index in its scope. How can I solve this problem ? Can I make ng-repeat, re plot itself after I make any changeI am just learning angular js, so please guide me if there is a better way to do such things.
<li ng-repeat="(featureIndex,feature) in result.features">
<span ng-bind="feature" contenteditable={{result.edit}}></span>
<i class="flr-always material-icons pointer" ng-show="result.edit" ng-click="remove([{key:'features',index:featureIndex}])">delete</i>
</li>
Here result.features is an array. So send $index from AngularJS template which will correspond to the array index which you want to delete.
e.g., ng-click="remove($index)"
then in controller
function remove(index){
$scope.result.features.splice($index, 1)
}
try this:
<li ng-repeat="feature in result.features">
<span ng-bind="feature" contenteditable={{result.edit}}></span>
<i class="flr-always material-icons pointer" ng-show="result.edit" ng-click="remove(feature )">delete</i>
</li>
and in remove function
function remove(feature){
var index = $scope.result.features.indexOf(feature);
if(index > -1)
$scope.result.features.splice(index, 1);
}
var app = angular.module("app", []);
app.controller('mainCtrl', function($scope){
$scope.result = {
features:
[
"ali","reza","amir"
]
};
$scope.remove = function(feature){
var index = $scope.result.features.indexOf(feature);
if(index > -1)
$scope.result.features.splice(index, 1);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.2/css/font-awesome.min.css" rel="stylesheet"/>
<div ng-app="app" ng-controller="mainCtrl">
<li ng-repeat="feature in result.features">
<span ng-bind="feature"></span>
<i ng-click="remove(feature)">delete</i>
</li>
</div>

Function not able to access observableArray in knockout

I keep getting this error when I try to update an observableArray:
'Unable to get property 'removeAll' of undefined or null reference'
Here is my code:
var agilityFirmViewModel = {
test: ko.computed(function () {
return Pairs[0].Pairs;
}),
currentLocation: ko.observableArray(Pairs[0].Pairs[0].Location);
//function to update values in currentLocation
ChangeLocation: function (practiceGroup) {
if (practiceGroup === undefined) {
practiceGroup = '(All Practice Groups)';
}
for (var i = 0; i <= Pairs[0].Pairs.length; i++) {
if (practiceGroup.Department === Pairs[0].Pairs[i].Department) {
this.currentLocation.removeAll();
this.currentLocation.push(practiceGroup.Location[i]);
return root.currentLocation;
}
}
},
}
$(document).ready(function () {
ko.applyBindings(agilityFirmViewModel);
});
Assuming that it goes through the if statement inside the for loop everytime,
whenever it gets to
this.currentLocation.removeAll();
I get the error above saying that currentLocation is undefined. I know that currentLocation has data in it, so would could be causing this issue. It's probably something simple, but I can't seem to figure it out. Thank you.
Where i call ChangeLocation():
<li class="nav-sidebar-GreenMenu">
<a href="javascript:;" class="draggable-panel" draggable="true">
<i id="CategoryIcon" class="glyphicon glyphicon-user"></i>
<span class="sidebarTabName"><b>Practice Group</b></span><br />
<!--For some reason, changing the margin-left below will change the width of the entire sidebar-->
<span id="CurrentItem_TPG" class="currentItem" #*style="margin-left:64px;"*#>(All Practice Groups)</span>
<span id="DefaultItem_TPG" style="display:none;">(All Practice Groups)</span>
<i class="fa fa-chevron-left pull-right hidden-xs" data-bind=""></i>
<span class="arrow open" style="margin-top:-30px;"></span>
</a>
<ul class="sub-menu">
<!--ko foreach: test()-->
<li>
</li>
<!-- /ko -->
</ul>
</li>
The problem is the way you're using bind. The actual signature for bind is:
fun.bind(thisArg[, arg1[, arg2[, ...]]])
Meaning, the first argument determines what this means in the function and the rest sets the arguments to use when it's called. Instead, try changing your click handler to this:
$parent.ChangeLocation.bind($parent, $data);
This ensures that ChangeLocation is called with $parent === this and $data === practiceGroup

Durandal 2.0 - Update the value of an observable in the view

I'm new to Durandal, my question has probably a very simple issue.
I load a list into a dropdown and the current value on the link which display the dropdown,
And the value of the link which display the dropdown is not updated correctly when an other value is selected.
But actually, I can't set the value of the observable in the select function.
View Model
var self = this;
self.system = require('durandal/system');
IPsKeys: ko.observableArray([]),
ipKeys: ko.observable(""),
activate: function (context) {
var that = this;
that.IPsKeys([]);
that.ipKeys("");
return $.when(
service.getIPSbyClientId(context.clientId).then(function (json) {
$.each(json, function (Index, Value) {
var ClientLobUWYear = {
NameLob: Value.LineOfBusiness.Name,
NameUWYear: Value.UnderwritingYear
};
that.IPsKeys().push(ClientLobUWYear);
// HERE MY VALUE IS GOOD UPDATING AND THE BINDING WORK
if (Index=== 0) {
that.ipKeys(ClientLobUWYear);
}
});
})
).then(function () {
//do some other datacontext calls for stuff used directly and only in view1
});
},
select: function (item) {
this.ipKeys = {
IdClient: item.IdClient,
IdLob: item.IdLob,
NameLob: item.NameLob,
NameUWYear: item.NameUWYear
};
/** PROBLEMS HERE **/
/** Uncaught TypeError: undefined is not a function **/
this.ipKeys(ClientLobUWYear);
},
View
<a id="select_lob-UWYear" class="dropdown-toggle" data-toggle="dropdown" href="#">
<span class="controls_value" data-bind="text: ipKeys().NameLob">ALOB</span>
<span class="controls_value" data-bind="text: ipKeys().NameUWYear">AYEAR</span>
</a>
<ul id="dropdown_year" class="dropdown-menu" data-bind="foreach: IPsKeys().sort(sortByLobYear)">
<li>
<a href="#" data-bind="click: $parent.select">
<span class="controls_value" data-bind="text: NameLob">Cargo</span>
<span class="controls_value" data-bind="text: NameUWYear">2014</span>
</a>
</li>
</ul>
Thanks a lot
The way you update an observable is like this:
var someObservable = ko.observable(""); //setting to "";
someObservable("Something else"); //updating to "Something else"
Not like this (which you are doing above)
var someObservable = ko.observable(""); //setting to "";
someObservable = "Something else";
This is overwriting someObservable with a string of value "Something else" and so is no longer an observable which is why it will not update the ui.
[JS Fiddle showing how to set observables.]

How to handle nested menu in knockout viewmodel

I am using knockoutjs in my project. I have a scenario where I have to create a nested menu in my viewmodel, which I did like this:
self.menu = [
{
name: 'Services',
sub: [{ name: 'Service-A' }, { name: 'Service-B' }]
},
// etc
];
self.chosenMenu = ko.observable();
self.goToMenu = function (main, sub) {
var selectedMenu = {
main: main,
sub: sub
};
self.chosenMenu(selectedMenu);
};
My View:
<ul class="nav navbar-nav menuitems col-md-8" data-bind="foreach: menu">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<span data-bind="text: name"></span></a>
<ul class="dropdown-menu" role="menu" data-bind="foreach: sub">
<li>
<a href="javascript:void(0);" data-bind="text: name,
click: function() { $root.goToMenu($parent, $data); }">
</a>
</li>
</ul>
</li>
</ul>
However, I feel that this approach of creating nested menu is not good, because suppose if I want to go on any menu item programmatically then with his approach it is not possible?
Can anybody please suggest me the good approach to handle this kind of scenario?
Make sure each menu item has a unique identifier. For the example data you've given name will suffice, but you may have to add a fullPath property to menu item view models.
Your goToMenu function can now take just one parameter: uniqueMenuIdentifier, and recurse through all menu items to find the correct one, like this:
function findMenuItem(menuList, uniqueMenuIdentifier) {
for (var i = 0; i < menuList.length; i++) {
if (menuList[i].name === uniqueMenuIdentifier) {
return menuList[i];
}
if (!!menuList[i].sub) {
var subItem = findMenuItem(menuList[i].sub, uniqueMenuIdentifier);
if (!!subItem) {
return subItem;
}
}
}
return null;
}
self.goToMenu = function (menuItem) {
var uniqueMenuIdentifier = menuItem.name;
var item = findMenuItem(self.menu, uniqueMenuIdentifier);
self.chosenMenu(item);
}
This allows for a much simpler binding in the anchor tag:
<a href="javascript:void(0);" data-bind="text: name, click: $root.goToMenu">
See this fiddle for a demo.
From this you can also guess that it's even possible to set the chosenMenu directly:
// No longer needed:
//function findMenuItem(menuList, uniqueMenuIdentifier) { }
self.goToMenu = function (menuItem) {
self.chosenMenu(menuItem);
}
See this fiddle for a demo.
I ran into a similar scenario yesterday. You can have a look at my solution on
Is there any knockout plugin for showing a nested context menu?. The main point is that I've used the template binding to be able to construct a hierarchical menu of any depth.

Categories