<p ng-repeat="row in matrix">
<span ng-repeat="column in row">
<input type="text" style="width: 20px; text-align: center;" ng-model="column" ng-change="{{column = }}">
</span>
</p>
And on my controller:
$scope.matrix = [[0, 0, 0], [0, 0, 0], [0, 0, 0]];
I have little piece of code and I want that little text input box to be associated with matrix[i][u]. I know I can use ng-model= to make the text box be associated with a certain variable.
However, I want it to go both ways - changing the variable will change the text box value and changing the text box value will change the variable. However, when I have ng-model on an input text box I can't seem to edit its value, as it'll always "reset" to its default.
I know I can use ng-change but I made the middle line this:
<input type="text" style="width: 20px; text-align: center;" ng-model="column" ng-change="update">
And it didn't work to call the $scope.update() function. I also still can't edit the text box value.
tl;dr: How can I have a text box with an ng-model and allow editing it to edit both the text box value and the variable on ng-model.
Use it this way:
<input type="text" ng-model="matrix[$index][$parent.$index]" style="width: 20px; text-align: center;" />
Example: http://jsfiddle.net/cherniv/hcLVE/
It is not very elegant , but it is working..
Here's a directive approach which is a little more fun:
app.directive("matrix", function($compile){
return{
scope:{
ngModel:'='
},
restrict:"E",
link:function(scope, element, attributes){
var render = function(){
var template="";
scope.ngModel.forEach(function(row, r){
template+="<p>";
console.log(scope.ngModel[r]);
row.forEach(function(column, c){
template+='<span><input style="width: 20px; text-align: center;" ng-model="ngModel['+r+']['+c+']"></span>';
});
template+="</p>";
});
element.html(template);
$compile(element.contents())(scope);
}
render();
scope.$watch('ngModel', render, true);
}
}
});
which can be used <matrix ng-model="matrix"></matrix>
Just because I love directives. Running here: http://plnkr.co/edit/jI7Hi9LKXnDFBd0gXtNZ?p=preview
Use
row[$index]
as the ng:model in the input tag:
<input type="text" ng-model="row[$index]" style="width: 20px; text-align: center;" />
The reason why this works and using column does not work is this: The <input> tag will create a child scope by copying the parent scope. But column is a simple/scalar variable. Such a variable will really just be copied. Therefore you end up with a copy in ng:model which is not connected to the real variable in your matrix. This is the reason why the AngularJS people stress that you should always have something with a dot inside referenced by ng-model.
On the other hand, row is still a complex variable (Array) and not a scalar. Such a variable is "copied" by JavaScript not by creating a real copy but by just copying the reference to the data. So you end up with a second reference to the same data. And therefore row in the child-scope created by the <input> tag is still connected to the original row data in the matrix and two-way data-binding will work.
To stress this again: Never use something without a dot as ng:model. AngularJS used to have bad examples doing this on their webpage but it appears that they have mostly/all been changed. But as you can see in this example something foo[5] is also ok, because it still references a complex variable. foo["bar"] would actually be equal to foo.bar.
Related
So the problem here is that I'm running ng-repeat through CSV data, and applying a ng-click to each corresponding widget to take the user to a new tab with that data.
It will work for one click and then from there it will register the click, and log to to the console but refuse to take me back to the tab via ng-click. Only by clicking the tab headers can I return to said tab.
What makes matters even more peculiar is identical code on another page works absolutely fine.
<uib-tabset active="activeForm">
<uib-tab index="$index" heading="Overview">
<rd-widget-body style="cursor:pointer;user-select: none;" ng-click="setTab($index)">
<uib-tab index="$index" ng-repeat="x in data | ragFilter" ng-click="setTab($index)" style="user-select: none; padding:0px 0px 0px 0px;">
Then in the controller:
$scope.setTab = function (newTab) {
$scope.activeForm = newTab;
}
It registers the fact that I'm clicking the widgets, it just won't set the tab more than once through the ng-click.
Turns out that because I held this functionality within an ng-if statement which creates and destroys a unique scope accordingly it wasn't tracking the int value assigned to activeform.
Assigning the int into an object as follows fixed the issue.
$scope.setTab = function (newTab) {
$scope.activeForm = { "i": newTab};
}
uib-tabset active="activeForm.i">
I'm simply trying to get an AngularJS expression to display on screen. However, nothing shows up between the curly braces. I've inspected the app with ng-inspector and although I see an object being created with an ng-model directive, I can't display the value with the object key.
Furthermore, for testing purposes, I can't even get a simple math expression to display either.
Here's what I'm working with.
<body ng-app="angularApp">
<div ng-controller="firstCtrl">
<input ng-model="project.completed" type="checkbox">
<input ng-model="project.title" type="text" placeholder="Project Title">
<label>
{{project.title}}
1+2={{1 + 2}}
</label>
<input ng-model="project.time" type="text" placeholder="Project Time">
<label for="">{{project.time}}</label>
<button ng-click="helloWorld()">Press Me</button>
</div>
</body>
...and here's the controller:
angular.module('angularApp', [])
.controller('firstCtrl', function($scope) {
$scope.helloWorld = function() {
console.log('You just pressed the button.');
};
$scope.project = {
completed :false,
title :'test',
};
});
The only thing that shows up in the label is '1+2='.
UPDATE: After spending a ridiculous amount of time trying to debug this I have been able to get the first value of the math expression to display -- the '1'. I achieved this by adding a space around the '+' operator. Still, the full expression is not evaluating.
If you're using another templating engine, such as Twig, Liquid, or Django, the curly braces may be being stripped out. This results in the values not displaying or evaluating properly.
The solution I found is editing the interpolation characters or $interpolateProvider like so inside your controller:
angular.module('angularApp', []).config(function($interpolateProvider){
$interpolateProvider.startSymbol('{[{').endSymbol('}]}');
})
Then, just wrap your expression in the new symbols, e.g.:
{[{ 1+2 }]}
...or
{[{ project.title }]}
I had the same issue and finally found it, simply open your web page and press f12 and view the console :) Also remove any unused css. Additionally make sure that you add the "ng-controller" in the tag or some other broad scope so its well covered within the scope.
My question is in regard of best practice / preferred readability in Angular 1.X with ng-show and ng-hide.
When using ng-hide and ng-show, is it advised to stick to one and to alternate the value I am evaluating or should i alternate between the two in order to keep the value in the expression the same?
See the following examples. Is one preferred over the other and if so why?
Assume that there are only two states, sportSelected can be Hockey or Football that is it, so there are two states.
Using only ng-show and switching the value
<div class="col-xs-4" ng-show="vm.sportSelected=='hockey'">
NJ Devils
</div>
<div class="col-xs-4" ng-show="vm.sportSelected=='football'">
NY Jets
</div>
<div class="col-xs-4" ng-show="vm.sportSelected=='football'">
NY Giants
</div>
Alternating between ng-show and ng-hide to keep the value the same
<div class="col-xs-4" ng-show="vm.isHockeySelected">
NJ Devils
</div>
<div class="col-xs-4" ng-hide="vm.isHockeySelected">
NY Jets
</div>
<div class="col-xs-4" ng-hide="vm.isHockeySelected">
NY Giants
</div>
The top seems more clear to me but it could just be due to poor method and variable names. I am looking through the angular documentation and I cant seem to arrive at what the preferred result is. Is one preferred over the other?
Edit: Flagged this to be closed, I realized this is pretty opinion based like tabs vs spaces even though I think one solution has benefits over the other
ng-hide and ng-show both work in different ways. They are essentially CSS classes which either hide or show the specified div, depending on how the value evaluates.
<!-- when $scope.myValue is truthy (element is visible) -->
<div ng-show="myValue"></div>
if myValue evaluates to true then the div would be visible
<!-- when $scope.myValue is falsy (element is hidden) -->
<div ng-show="myValue" class="ng-hide"></div>
however, in the second example, the div would be hidden as the class is set to that of ng-hide.
also you can run ng-show or ng-hide to check if the value evaluates to false, like so: <div ng-show="!myValue"></div>
Due to the nature of the digest cycle in Angular, these checks will be ran on page load. If you do not want the div to be shown on the page, it can be recommendable to use ng-if, rather than ng-show or ng-hide, as it will not load on the page, as opposed to simply hiding it.
In the snippet below you will see an example working for both ng-hide and ng-show, using the value of the ng-model value response of the input checkbox 'checked'. Which gives a boolean response.
When it is clicked on, the value for 'checked' evaluates to true. When it is unclicked, the value evaluates to false. When the ng-model evaluates to false, it shows the ng-hide div, when the ng-model evalutes to true, it shows the ng-show div.
Further reading here: Angular ng-show documentation
#import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
.animate-show {
line-height: 20px;
opacity: 1;
padding: 10px;
border: 1px solid black;
background: white;
}
.animate-show.ng-hide-add, .animate-show.ng-hide-remove {
transition: all linear 0.5s;
}
.animate-show.ng-hide {
line-height: 0;
opacity: 0;
padding: 0 10px;
}
.check-element {
padding: 10px;
border: 1px solid black;
background: white;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example - example-ng-show-production</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular-animate.js"></script>
</head>
<body ng-app="ngAnimate">
Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngHide"><br/>
<div>
Show:
<div class="check-element animate-show" ng-show="checked">
<span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
</div>
</div>
<div>
Hide:
<div class="check-element animate-show" ng-hide="checked">
<span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
</div>
</div>
</body>
</html>
<!--
Copyright 2016 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
-->
Whether or not you use ng-hide or ng-show should be based on how you want the page to appear by default. If you are controlling the visibility of an element that will be hidden by default and only shown after the user completes some action (like selecting a sport), then you want to use ng-show. If the element is to be shown by default and only hidden after some user action (maybe a div that says 'select a sport' that disappears once a sport is selected), then you want to use ng-hide.
Using the directives this way will contribute more toward readability than worrying about how the boolean condition itself is specified. It also has an important practical benefit. If you use ng-hide for something that is supposed to be hidden by default, you might see the element flicker each time you load the page, because in early $digest cycles before your scope can be fully evaluated, the result of that condition will be falsy, which will cause the element to appear briefly before it disappears.
You've got the right idea in the top example (looks like you have a syntax issue with the quotes though).
My html:
<div id="contentDiv">
<div id="headerDiv" ><div id="titleDiv"> Queries</div></div>
<div id="valuesDiv" ><div id="yearDiv"> 2015</div></div>
<div id="graphDiv" ><div id="chartDiv">graph</div></div>
</div>
Like this div, I have another div but the content in the div is different.
How to add a new div horizontally when I click on hyperlink using angularjs?
How can I do this? please help me out regarding this
Looks like what you need is a two way binding with the ng-model directive. So the idea would be that you bind the new div to a variable in your scope which is initially in an empty or undefined state (for example, there are better ways). When the hyperlink is clicked it calls the function specified by an ng-click directive which will fill your bound object, which in turn will cause the new div to be rendered.
EDIT:
Based on your comments here is a simple example.
HTML page:
<div id="newDiv" ng-repeat="item in items">
<!-- Div content -->
<!-- example -->
<input type="text" ng-model="item.name">
</div>
<input type="button" ng-click="addItem()">
Controller:
$scope.items=[];
$scope.addItem = function() {
var newItem = {};
newItem.name = "new item name";
$scope.items.push(newItem);
}
What's happening here is the data for each div is stored in an array of objects. The ng-repeat directive will repeat the div for each object in the array. You can then fill the elements in the div using the object. Adding a new div is as simple as adding a new item to the array and angular will take care of the rest for you. Please note that I have not tested this example, but hopefully it's enough to point you in the right direction.
RE aligning the divs horizontally, this will be done with CSS, using the inline-block display mode. So you could give the div a class of, for example, "horizontalDiv" and add the following class to your CSS file:
.horizontalDiv {
display: inline-block;
}
How can I sucessfully do this?
ng-class="{'a':x, 'b':::y}"
Notice how I'm trying to bind only once with "y" but not with "x"
I also tried using multiple ng-class directives, like this:
<div ng-class="{'a':x}" ng-class="::{'b':y}"></div>
but doesn't work either.
The problem is that you can only specify one-time binding syntax :: at the beginning of the expression. Here your expression is an object literal and using :: before the second key value results in an invalid syntax. You would have to split them up and probably place one section in the class expression (There is no point using 2 ng-class directives).
Example:
ng-class="{'a':x}" class="someclass {{::{true:'b'}[y]}}"
Documentation
An expression that starts with :: is considered a one-time expression. ....
.a {
color: green;
}
.b {
color: blue;
}
.a.b {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js"></script>
<div ng-app>
<div ng-class="{'a':x}" class="{{::{true:'b'}[y]}}">Test</div>
X->
<input type="checkbox" ng-model="x">Y->
<input type="checkbox" ng-model="y">
</div>
Note: One time binding will keep the watch until it gets an non undefined value for the bound property. If the property value is available at the time view renders (i.e not asyncronous) you could just do
<div ng-class="{'a':x}" class="{{::y ? 'b': ''}}">Test</div>
as well.