Cannot set a value in $scope in Angular? - javascript

I am following the tutorial on Lynda.com for AngularJS essential training.
Part of my index file looks like:
<div class="container" ng-controller="AppCtrl">
<h1>AngulAir</h1>
<ul class="nav nav-pills">
<li role="presentation" ng-class="destinationsActive">Destinations</li>
<li role="presentation" ng-class="flightsActive">Flights</li>
<li role="presentation" ng-class="reservationsActive">Reservations</li>
</ul>
<div ng-view>
</div>
<p>{{ flightsActive }}</p>
</div>
Now when I click on any link it should fire the setActive function defined in the AppCtrl which looks like this:
$scope.setActive = function (type) {
$scope.destinationsActive = '';
$scope.flightsActive = '';
$scope.reservationsActive = '';
$scope[type + 'Active'] = 'active';
};
Now the problem is very simple. The function should take the type for example 'destinations' and append 'Active' to it and set the scope variable 'destinationsActive' to active which in turn should be reflected in the ng-class directive of the li tags and the link should be active.
I have tried to insert alert('hello'); after setting it active which fires up. Now this means that the function is indeed being called. But when I do alert($scope.destinationsActive); it gives me a blank alert whereas it should give me active as the value.
I am not following with the exercise files and I feel that maybe because the tutorial is relatively older, there might be changes in the framework. I have already encountered such problems with the tutorial. Anyway, what is it that I am doing wrong?

In your ng-click directives you are passing the argument as a variable, not a string.
ng-click="setActive(destinations)"
Will pass in the value of the $scope.destinations, which is undefined. Try passing in a string i.e.:
ng-click="setActive('destinations')"
Note the single quotes

You need to put parenthesis around the parameters in your html javascript function call.
Destinations
Here is a working example: JSFiddle

I would recommend you to think of the model binding in more semantic way. For example use a checkbox instead of link and set the checkbox value as ng-model to a scope variable instead.
<input type="checkbox" ng-model="destinations">
<input type="checkbox" ng-model="flights">
<input type="checkbox" ng-model="reservations">
and thereafter use the model to reflect the rest of the changes (this is the answer to the original question, you have to specify a classname and a condition in brackets:
<li ng-class="{ destinationsActive: destinations }">

Pass argument as string in ng-click.
working code : http://jsfiddle.net/Virbhadrasinh/cLsLfkjm/

Related

How to copy ngRepeat content into another div?

I'm listing a json file using angular, like this:
html:
<li ng-repeat="task in tasks">
<h1>{{task.title}}</h1>
<small>{{task.date}}</small>
<p>{{task.details}}</p>
<button ng-click="details($event)" data-title="{{task.title}}" data-date="{{task.date}}" data-details="{{task.details}}"></button>
</li>
js:
$scope.details = function(obj){
var title = obj.target.getAttribute('data-title'),
date = obj.target.getAttribute('data-date');
...
}
I pass all content via data-attributes, when I click on <button> it calls the ng-click and I access all data-attributes via pure javascript and create a <div> to wrap those contents. This way is working just fine, but is there an easier way to get those values via angular?
Much simpler and proper angular way, yes just pass task though the ng-click function expression and access it from your handler and say goodbye to DOM access from the controller (which is anyways bad) and data attributes:-
<li ng-repeat="task in tasks">
<h1>{{task.title}}</h1>
<small>{{task.date}}</small>
<p>{{task.details}}</p>
<button ng-click="details(task)"></button>
</li>
and
$scope.details = function(task){
console.log(task);
//console.log(this.task);
}
Plnkr

Bind part of ng-model with scope in angularjs

In my application i have array of colors and i want to create a list of colors with checkbox.
var app = angular.module('app',[]);
app.controller('mainCtrl',function($scope){
$scope.colors = ['red','blue','green','yellow'];
});
so i create an ng-repeat to create a list :
<body ng-controller="mainCtrl">
<ul>
<li ng-repeat="c in colors">
<input type="checkbox" ng ng-true-value="{{c}}" ng-false-value=""/> {{c}}
</li>
</ul>
</body>
now i need to bind ng-model of each checkbox to something like f.tags.red or f.tags.blue so i change the code to something like this :
<li ng-repeat="c in colors">
<input type="checkbox" ng-model="f.col.{{c}}" ng-true-value="{{c}}" ng-false-value=""/> {{c}}
</li>
but this make my app broken.so ho to fix this for ng-model and ng-true-value also i create this jsbin .
thanks
There were a few things going wrong here. In general, inside properties of Angular that takes expressions (check the docs), you should not use {{x}}, but rather just x itself. So, you'r ng-model should not be f.col.{{c}} but rather f.col.blue and f.col.red etc. Now, in javascript, doing a.b and a['b'] is identical, so in this case, since c is a string, the correct model is f.col[c]. The same goes for the true-value, it should also simply be c.
Lastly, to get the example working, you need to actually create the objects maintaining your model (in this case $scope.f.col. Working example can be seen here: http://jsbin.com/citupepa/1/edit
Here is working demo for selection of colors:
jsbin
<ul>
<li ng-repeat="c in colors">
<input type="checkbox" ng-model="f.col[c]" ng-true-value="true" ng-false-value="false"/> {{c}}
</li>
Selected Colors: {{f.col}}

AngularJs - Holding value of for loop string to use elsewhere

I've come a bit stuck in my angularjs project.
I run a for loop to query some nested JSON data and output it in 3 different variables inside an ng-repeat. So it makes up a title where i have the control over the elements that make up the title {{ number }} {{ shots }} {{ goals }}.
However, my knowledge of angularjs is stretched here because when I click on one of the events (from the ng-repeat list) it gives me a new tab, but I want to bring the title of that event to the new tab.
I can't call it as a scope variable as the last variable is still being held in there. I thought about assigning it as a new variable.. but was unsure how to actually do that in angularjs.
Here is the code i'm working with:
<li ng-repeat="event in events.events">
<div ng-if="actionType(event)" >
{{number}}
{{shots}}
{{goals}}
</div>
<a class="showPlayer" ng-click="showPlayer(event)">
View more stats
</a>
</li>
my angularjs is just a standard for loop which looks for values inside the js and assigns them as variables.
Any advice is very much appreciated.
EDIT: 24 hours later and I still can't crack this (very frustrating).
I'm not sure if there is a way to grab the string from the ng-click and clone that?
I don't want to have to run another check for the title when I already have the information, surely there is an 'angular' way to do this??
Please try this I am not sure but it might help you
<li ng-repeat="event in events.events">
<div ng-if="actionType(event)" >
{{event.number}}
{{event.shots}}
{{event.goals}}
</div>
<a class="showPlayer" ng-click="showPlayer(event.number,event.shots,event.goals)">
View more stats
</a>
</li>
Try using $rootScope.
Define a rootscope variable where event is handled and write your title in html like you did. {{title}}
$rootScope.title = "example";

Bind ng-models in input type checkbox

I have a problem when binding ng-models with ng-repeat in a input tag type checkbox.
I will first attach my code and then explain more in detail.
app/main.html:
<div ng-repeat="feature in features">
<input type="checkbox" ng-model="features[$index].name">{{features[$index].name}}
</div>
<br></br>
<div class="highlighter">
<span ng-class="{emo:Emotions}">Manually</span> <span ng-class="{feel:Feelings}">create</span> the <span ng-class="{emo:Emotions}">entire</span>
</div>
main.js
angular.module('webClientApp')
.controller('MainCtrl', function ($scope,$http) {
[...other variables...]
$scope.features = [{'name':'Emotions'},{'name':'Feelings'}];
[...other parts of code]
});
Let's also assume that in the main.css file there are references to the classes .emo' and.feel' respectively to highlight the target word when the user ticks the box relative to the feature.
Now, the application works correctly when I listed all the inputs one by one like the following:
<input type="checkbox" ng-model="Emotions">Emotions
<input type="checkbox" ng-model="Feelings">Feelings
but I wanted to wrap it into an ng-repeat and list the features in the controller scope, since the features I will considered will be more. When I try the code above when I tick on the box the name changes to `true'.
I have read a lot about how to bind models to an ng-repeat inside a input tag but none of the solutions apply to my case.
Can someone please help me?
I changed thigs up quite a bit from your original model but... I did get something to behave similar to what you are looking for.
HTML
<div ng-app="webClientApp">
<div ng-controller="MainCtrl">
<div ng-repeat="(feature,enabled) in features">
<input type="checkbox" ng-model="features[feature]">{{feature}}</input>
</div>
<div class="highlighter">
<span ng-class="{emo:features.Emotions}">Manually</span> <span ng-class="{feel:features.Feelings}">create</span> the <span ng-class="{emo:features.Emotions}">entire</span>
</div>
{{features}}<br>
{{features.Emotions}}<br>
{{features.Feelings}}
</div>
JS
var app = angular.module('webClientApp', []);
app.controller('MainCtrl', function($scope, $http) {
$scope.features = {Emotions: true, Feelings: true};
});
Here's the fiddle: http://jsfiddle.net/rodhartzell/8YrxQ/
Hope this helps.
(i should add this as a comment, but I don't have enough rep. yet)
There is an issue on github which concerns your issue: https://github.com/angular/angular.js/issues/1404 and the comment of caitp shows some workarounds: https://github.com/angular/angular.js/issues/1404#issuecomment-30859987
You could (also) define a new javascript object in your controller and map the elements to that.
In controller: $scope.awnsers = {};
In template: ng-model="awnsers[feature.name]"
I hope this helps
You must use ng-checked instead of ng-model.
Check out this jsfiddle
http://jsfiddle.net/fizerkhan/z5z9s/24/
ngModel and ngChecked are not meant to be used together.
ngChecked is expecting an expression, so by saying ng-checked="master". If the expression is truthy, then special attribute "checked" will be set on the element
You should be able to just use ngModel, tied to a boolean property on your model. If you want something else, then you either need to use ngTrueValue and ngFalseValue (which only support strings right now), or write your own directive.

Most Angular way to add class on click

I'm building an interface with a lot of toggles to control what data is being filtered in a different part of an App's search results. Here is a codepen of it: Here
Coming from a jQuery/Backbone background, what is the most Angular way of toggling the 'active' state of any/all of the filter items? Essentially, almost any <li> tag presented here is a toggle-able feature.
In jQuery, I would put a listener on the view and wait for any click events to bubble up and toggle an 'active' class on the event.target. I want to do it the best way with Angular.
(Also, this is my first Angular project.. I am probably doing all sorts of things the wrong way. Apologies in advance.)
Edit: To clarify the question, I have an App Interface with 20+ possible filter attributes to control a separate module on the page. Every time someone toggles one of these filter attributes, I want to add/remove an 'active' class. Do I put an 'ng-click="function(...)"' in the ng-repeat for each controller? Or is there an easier way to manage this module-wide behavior (a la event bubbling, like in Backbone/jQuery) ?
Thanks!
You can do something like this:
<section ng-init="active = 'areaFoo'">
<div ng-class="{active:active == 'areaFoo'}" ng-click="active = 'areaFoo'"></div>
<div ng-class="{active:active == 'areaBar'}" ng-click="active = 'areaBar'"></div>
</section>
It will populate $scope.active for you, and is very angular as it leverages existing directives, manages the state on scope, and does not leverage dom api's or events outside of directives. There is really no need to involve the controller here, as its display logic.
Learn more about ng-class here.
Multiple active elements
<section>
<div ng-class="{active:areaFoo}" ng-init="areaFoo = true">
<button ng-click="areaFoo = true">activate</button>
<button ng-click="areaFoo = false">de activate</button>
</div>
<div ng-class="{active:areaBar}" ng-init="areaBar = false">
<button ng-click="areaBar = true">activate</button>
<button ng-click="areaBar = false">de activate</button>
</div>
<div ng-class="{active:areaBar}" ng-init="areaBaz = false">
<button ng-click="areaBaz = true">activate</button>
<button ng-click="areaBaz = false">de activate</button>
</div>
</section>
you could also toggle with something like this ng-click="areaFoo = !areaFoo"
I was able to come up with a solution I'm ok with, for anyone curious you can see a demo Here.
Here are the relevant code snippets:
<li ng-repeat='category in data' ng-class='{active: category.isActive}' ng-click='toggleActive(category)' >
<span class='solr-facets-filter-title'>{{category.catTitle}}</span>
<span class='solr-facets-filter-count'>{{category.catResults}}</span>
</li>
An ng-click calls a method on the Controller, toggleActive(category). The current data model gets sent to the method. In the JS:
$scope.toggleActive = function(category){
category.isActive = !category.isActive;
}
The function returns the opposite of the isActive attribute back to the li in question: an ng-class adds the active class for a truthy state of isActive.
I'm not a huge fan of how I have to adjust the data model with flags for active/inactive states like this, but it ends up working out for the best in this case. I can push those isActive states back to the $scope so that other parts of the App can run queries based on that information.

Categories