Angular way of toggle md-button inside ng-repeat - angularjs

I have some 10 buttons inside ng-repeat which basically operate like a switch to get multiple data, each of the button must pass a value to controller and in controller push that value to an array on first click and delete that value in next(toggle action).
My html code segment
<md-button id="{{choice.id}}btn{{ambutton}}" ng-repeat="ambutton in ambuttons" ng-click="getTime(choice,ambutton);" class="md-fab md-primary" ng-class="{'active md-warn': variable,'disable md-primary': !variable}">{{ambutton}}</md-button>
Controller function
$scope.ambutton=[1,2,3,4,5,6,7,8,9,10]
$scope.getTime = function (choice,ambutton) {
$scope.variable = !$scope.variable;
if($scope.variable){
//save the value to an array;
}
else{
//remove the value from array
}
};
Problem facing is when i click a button all the button becomes active, i tried adding differnt variables for each button like variable0,variable1,variable2... (by adding variable{{ambutton}}) and in controller using if-elseif it's working fine, But i need a better solution can anything possible with id related to each button?

check this out http://jsfiddle.net/n2p1ocqz/7/
you can use variables as an array and with index manipulate, whether choose or not, like
$scope.ambuttons=[1,2,3,4,5,6,7,8,9,10]
$scope.variables=[];
$scope.getTime = function (choice, ambutton, index) {
$scope.variables[index] = !$scope.variables[index];
if($scope.variable[index]){
//save the value to an array;
}
else{
//remove the value from array
}
};
and your partial like
<md-button ng-repeat="ambutton in ambuttons track by $index" ng-click="getTime(choice, ambutton, $index);" class="md-fab md-primary" ng-class="{'active md-warn': variable,'disable md-primary': !variables[$index]}">{{ambutton}}</md-button>

Related

How can I prevent my custom directive from getting compiled/executed every time I use $route.reload()

I have built a custom directive to enable arrow key navigation in a dropdown.
This is my HTML code
<div ng-click="dropdownShow = !dropdownShow" id="dropdownToggle" arrow-navigation>
{{currentlySelectedItem}}
</div>
<div ng-show="dropdownShow">
<div ng-repeat="item in list" id="row_{{$index}}" ng-click="getItemInfo($index)">
<span>{{item}}</span>
</div>
</div>
And my JS code
app.directive('arrowNavigation', ['$document', function($document){
return{
restrict: 'A',
link: function(scope, element, attrs){
$document.bind('keydown',function(e){
// check if dropdown open
if(scope.dropdownShow){
// if down arrow key pressed
if(e.keyCode === 40){
console.log("down arrow key pressed");
// When the dropdown is first opened, the focus will be on the dropdownToggle.
// In this case, I'm moving the focus to the first item on the list.
if(document.activeElement.id === "dropdownToggle"){
document.getElementById('row_0').focus();
}
else{
let currentFocused = document.activeElement.id;
// currentFocused = row_ + $index
let index = currentFocused.substring(4);
// index = $index of currently focused item
console.log(index);
index++;
// check if the currently focused item is the last item on the list
// In this case, move the focus back to the first item on the list
if(index >= scope.list.length){
document.getElementById('row_0').focus();
}
else{
document.getElementById('row_' + index).focus();
}
}
e.preventDefault();
}
// there's similar code for up arrow key press. I have decided to skip it for the sake of simplicity.
}
})
}
}
}])
The first time I use the dropdown, everything works perfectly.
But when I select any item from the dropdown, the resulting ng-click function has a $route.reload inside it. This causes my ng-view to get reloaded. That's when the problem starts. After the first reload, when I try to use the dropdown, it gets executed twice for every single arrow click. So if the first list item is focused, and I press the down arrow key, instead of moving the focus to the second item, it moves the focus to the third item. Upon every subsequent $route.reload(), the number of executions increases by one.
I'm guessing that this is happening cause everytime the route gets reloaded, the directive is being re-rendered, causing multiple copies of the same directive, all of which then get executed on the arrow click.
Is there any way to prevent this re-rendering?
Remove the event listener when scope is destroyed
// inside link
scope.$on("$destroy", function() {
$document.unbind('keydown')
});
Note that angular.element bind and unbind are deprecated so am assuming you may be using a fairly old version. Most recent versions use on() and off()

angular- how to hide one element and show another with ng-blur?

I want to hide this div:
<div class="desc" ng-show="desc">
and show this div
<div class="lists"ng-show="lists"
ng-repeat="x in todoWork | orderBy:['todoPriority', 'todoTime']"
ng-class="{strike:x.done}">
on ng-blur directive.
I tried this but,
$scope.myFunc1 = function() {
if($scope.myForm1.description.$dirty && $scope.myForm1.datetime.$dirty && $scope.myForm1.priority.$dirty==true){
$scope.lists =true;
$scope.desc=false;
}
};
but only first one is executing.Even if try to write another function for second one the problem remains.
if you want to hide first one and show second one then why are not you using a single variable like the below:
First one <div ng-show="desc">
Second one <div ng-show="!desc">

Change Single Button Color from ngRepeat generated button list

I'm using ngRepeat to generate four buttons. Whenever I click one of the buttons, I want to change its color and also execute a function (for now, I'm just using console.log for sake of simplicity). If I click on another button, I want to change its color while reverting the previous button back to its original color.
I have a couple of issues - the first is that I can't seem to get ng-click to accept two commands (the first being the console.log function and the second being the instruction to change the button color). The other issue is that if I take out the console.log function, I end up changing all of the buttons when I click on one.
Any ideas? Here's the plunkr: http://plnkr.co/edit/x1yLEGNOcBNfVw2BhbWA. You'll see the console.log works but the button changing doesn't work. Am I doing something wrong with this ng-click?
<span class="btn cal-btn btn-default" ng-class="{'activeButton':selectedButt === 'me'}" ng-click="log(element);selectedButt = 'me'" data-ng-repeat="element in array">{{element}}</span>
You can create a simple function in your controller which handles this logic:
$scope.selectButton = function(index) {
$scope.activeBtn = index;
}
Then, you can simply check in your template if the current button is active:
<span class="btn cal-btn btn-default" ng-class="{true:'activeButton'}[activeBtn == $index]" ng-click="selectButton($index);" ng-repeat="element in array">{{element}}</span>
I also changed your plunkr
You may convert your element list from string array to object array first.
$scope.array = [
{"name":"first", "checked":false},
{"name":"second", "checked":false},
{"name":"third", "checked":false},
{"name":"fourth", "checked":false}
];
And your log function need to change to:
$scope.log = function(element) {
console.log(element.name);
angular.forEach($scope.array, function(elem) {
elem.checked = false;
});
element.checked = !element.checked;
}
Then, in your HTML:
<button class="btn cal-btn"
ng-repeat="element in array"
ng-click="log(element)"
ng-class="{activeButton: element.checked, 'btn-default': !element.checked}"
>{{element.name}}</button>
Please see the updated plunker here.

How to expand/collapse all rows in Angular

I have successfully created a function to toggle the individual rows of my ng-table to open and close using:
TestCase.prototype.toggle = function() {
this.showMe = !this.showMe;
}
and
<tr ng-repeat="row in $data">
<td align="left">
<p ng-click="row.toggle();">{{row.description}}</p>
<div ng-show="row.showMe">
See the plunkr for more code, note the expand/collapse buttons are in the "menu".
However, I can't figure out a way to now toggle ALL of the rows on and off. I want to be able to somehow run a for loop over the rows and then call toggle if needed, however my attempts at doing so have failed. See them below:
TestCase.prototype.expandAllAttemptOne = function() {
for (var row in this) {
if (!row.showMe)
row.showMe = !row.showMe;
}
}
function expandAllAttemptOneTwo(data) {
for (var i in data) {
if (!data[i].showMe)
data[i].showMe = !data[i].showMe;
}
}
Any ideas on how to properly toggle all rows on/off?
Using the ng-show directive in combination with the ng-click and ng-init directives, we can do something like this:
<div ng-controller="TableController">
<button ng-click="setVisible(true)">Show All</button>
<button ng-click="setVisible(false)">Hide All</button>
<ul>
<li ng-repeat="person in persons"
ng-click="person.visible = !person.visible"
ng-show="person.visible">
{{person.name}}
</li>
</ul>
</div>
Our controller might then look like this:
myApp.controller('TableController', function ($scope) {
$scope.persons = [
{ name: "John", visible : true},
{ name: "Jill", visible : true},
{ name: "Sue", visible : true},
{ name: "Jackson", visible : true}
];
$scope.setVisible = function (visible) {
angular.forEach($scope.persons, function (person) {
person.visible = visible;
});
}
});
We are doing a couple things here. First, our controller contains an array of person objects. Each one of these objects has a property named visible. We'll use this to toggle items on and off. Second, we define a function in our controller named setVisible. This takes a boolean value as an argument, and will iterate over the entire persons array and set each person object's visible property to that value.
Now, in our html, we are using three angular directives; ng-click, ng-repeat, and ng-show. It seems like you already kinda know how these work, so I'll just explain what I'm doing with them instead. In our html we use ng-click to set up our click event handler for our "Show All" and "Hide All" buttons. Clicking either of these will cause setVisible to be called with a value of either true or false. This will take care of toggling all of our list items either all on, or all off.
Next, in our ng-repeat directive, we provide an expression for angular to evaluate when a list item is clicked. In this case, we tell angular to toggle person.visible to the opposite value that it is currently. This effectively will hide a list item. And finally, we have our ng-show directive, which is simply used in conjunction with our visible property to determine whether or not to render a particular list item.
Here is a plnkr with a working example: http://plnkr.co/edit/MlxyvfDo0jZVTkK0gman?p=preview
This code is a general example of something you might do, you should be able to expand upon it to fit your particular need. Hope this help!

unable to get ng-checked property for a radio button to check the button when populating a form

EDIT: for those of you who don't want to go through the code, I'm basically passing the form a "node" object with node.selectedAnswer = "4,1,4" or some string like that. The form has radio buttons and one of the buttons has a value "4,1,4". the radio button also has ng-checked="node.selectedAnswer" expression. But that doesn't work. I know for sure that node.selectedAnswer has the appropriate value.
I have a series of radio button questions that I'm asking the user. I want them to be able to go previous and next. I'm using a stack to store the data retrieved from ajax call, as well as selectedAnswer when they select an option and click next. I've commented the code itself to explain the situation where I can. Everything seems to be working, except ng-checked is just not picking up node.selectedAnswer, even though I can output {{node.selectedAnswer}} properly to the page.
<div class="container-fluid" ng-app="AccountRequest" ng-controller="GameNode" ng-init="outside={}">
<div class="row-fluid">
<div class="span2"></div>
<div class="span10">
<form>
<!-- node.selectedAnswer displays the selectedAnswer correctly when clicking previous and going back.
However, ng-checked is somehow not selecting the appropriate radio button. -->
<span>{{node.Question.Text}} selected answer: {{node.selectedAnswer}}</span>
<div class="radio" ng-repeat="answer in node.Answers">
<input type="radio" id="answerGroup" name="answerGroup" ng-checked="node.selectedAnswer" ng-model="outside.selectedAnswer"
value="{{answer.BranchId}},{{node.LeafId}},{{answer.Id}}"/> {{answer.Text}}
</div>
<div>
<input type="button" ng-click="previous()" value="Previous"/>
<input type="button" ng-click="next(outside.selectedAnswer)" value="Next"/>
</div>
</form>
</div>
</div>
</div>
//below is the script
app.controller('GameNode', function ($scope, $http) {
var nodes = [];
function load(branchId, leafId, answerId) {
$http.get("/AccountRequest/GetNode?branchId=" + branchId +
"&leafId=" + leafId +
"&answerId=" + answerId)
.success(function (data) {
//get data and push it in the stack
nodes.push(data);
$scope.node = data;
});
}
function populateValues(selectedAnswer) {
var answer = null;
if (selectedAnswer === undefined || selectedAnswer == null)
selectedAnswer = "0,0,0";
//when next is clicked, retrieve the selectedAnswer from form and store it in current node as a property.
if (nodes.length > 0) {
var curNode = nodes.pop();
curNode.selectedAnswer = selectedAnswer;
nodes.push(curNode);
}
answer = selectedAnswer.split(',');
if (answer != null) {
load(answer[0], answer[1], answer[2]);
}
}
$scope.next = populateValues;
$scope.previous = function () {
//when previous is clicked, pop the current node out and throw it away.
//then pop the previous node out, read it, and push it back in as current node.
if (nodes.length > 1) {
nodes.pop();
var prevNode = nodes.pop();
nodes.push(prevNode);
$scope.node = prevNode;
}
};
populateValues();
});
Older Answer - This works, (was marked correct) but using $parent can get a bit messy in nested repeats.
In this instance, you don't need to use ng-checked at all. Since this is a radio group, the checked attribute will be bound to the model. If the model is bound to the value of an individual radio button, then your ability to change which button is "checked" becomes very simple.
Here is a plunk that demonstrates the concept.
So in your case a few changes need to be made.
1. Get rid of 'id' attribute - the ID must be unique for each element.
2. Each item created in an ng-repeat creates its own child scope. So to access the original model, "$parent" must be invoked.
<input type="radio" name="answerGroup" ng-model="$parent.someAnswerAttribute"
value="{{answer.BranchId}},{{node.LeafId}},{{answer.Id}}"/>
In your controller define the model as you already did, then modify it to be tied to a value of a button, which in your case will be a bit lengthy, since you have multiple attributes within your value.
$scope.someAnswerAttribute = // exactly what the value of a radio button would be.
Again, the plunker above reflects this concept. Hope this helps!
..
..
Edit - Better Answer:
Since the ng-repeat creates its own child scope, and two-way binding is necessary, the ng-model should be referencing an object instead of a primitive. In other words, if the model was $scope.myModel="Biff", the child scope can not access that without invoking $parent (in the answer below). However, if the model is referencing a property of an object, the child will receive prototype inheritance of that object. (I think I said that right).
So using the older answer example, we can change:
From this in the parent controller:
$scope.someAnswerAttribute = "Biff";
To this in the parent controller:
$scope.someAnswerAttribute = {value: "Biff"}
And in the radio group:
<input type="radio" name="answerGroup" ng-model="someAnswerAttribue.value"
value="{{answer.BranchId}},{{node.LeafId}},{{answer.Id}}"/>
This plunk is forked from the older answer and demonstrates model as an object property.

Resources