I have a snippet of html which I'd like to hide if a variable $scope.city is empty html:
<div class="col-lg-12" **ng-hide="{{city === ''}}"**>
<h1>{{forecast.data.city.country}} ,{{forecast.data.city.name}} </h1>
<h2>Forcast for : {{city}}</h2>
</div>
<div class="col-lg-8">
<div class="input-group">
<span class="input-group-addon" id="basic-addon1">City#</span>
<input type="text" **ng-model="city"** class="form-control" placeholder="Username" aria-describedby=" basic-addon1">
</div>
</div>
even though they are bound the element does not hide in real time, only if I go to that page with already empty $scope.city variable , there is a one more variable city which comes from varService (I use it to share variable between multiple controllers) here is Angular Code:
app.controller('forecastController', ['$scope','varService','$http', function($scope,varService,$http){
$scope.$watch('city', function() {
varService.city = $scope.city;
});
$scope.city = varService.city;
$scope.numOfDays = 2;
$scope.days = 2;
$scope.$watchGroup(['days', 'city'], function() {
$http.get('http://api.openweathermap.org/data/2.5/forecast?q='+$scope.city+'&mode=json&appid=e652a2c384655ea24f5b12d2fb84c60f&cnt='+$scope.days+'&units=metric')
.then(function(data) { $scope.forecast = data; });
});
}]);
so how do I make ng-hide work in real time as my $scope.city changes ? Thanks.
Instead of
ng-hide="{{city === ''}}"
Write it like this
ng-hide="city.length===0"
city is already bound to $scope in your controller, and ng-hide/ng-show expects an expression. so you don't need to use the double curly brackets({{}}) to evaluate it to true or false, just provide the expression as as like so "city.length===0".
try this;
ng-hide="city == ''"
Change your code use ng-if instead of ng-hide, because ng-if does not create element
<div class="col-lg-12" ng-if="!city.length">
<h1>{{forecast.data.city.country}} ,{{forecast.data.city.name}} </h1>
<h2>Forcast for : {{city}}</h2>
</div>
OR
<div class="col-lg-12" ng-hide="city.length">
<h1>{{forecast.data.city.country}} ,{{forecast.data.city.name}} </h1>
<h2>Forcast for : {{city}}</h2>
</div>
Related
I have a strange situation in which $scope variables binding do not appear to be work as expected.
Here is the HTML:
<div class="input-group" style="width:100px">
<input type="number"
class="form-control"
id="Sampling_Request_for_Current_Sampling_INPUT"
ng-model="aabbcc"
style="width:125px;text-align:center">
<span class="input-group-btn">
<button class="btn btn-default" ng-disabled="Cannot_Allocate_Yet" ng-click="Get_Sampling_Request_Details()" type="button">{{All_Labels.Common.Display}}</button>
</span>
</div>
and here is the scope function invoked upon clicking on the button:
$scope.Get_Sampling_Request_Details = function () {
console.log("$scope.aabbcc: " + $scope.aabbcc) ;
}
The variable $scope.aabbcc is initialized to 0 upon controller's loading.
Regardless what I type into the input element, I always get 0 in the console.
This scenario generally happens, If you have wrapped your HTML inside ng-if, ng-switch ng-repeat.. or some other directive that creates new child scope.
See this fiddle.
So it's a best practice to wrap your scope in some model to leverage protypical inheritance and correctly bind data to $scope.
Like : $scope.data.aabbcc = 0 and use it like ng-model ='data.aabbcc'.
See this for few minutes and Read this for complete understanding.
check this working example
<div ng-controller="MyCtrl">
Hello, {{name}}!
<input type="number" ng-model="name"/>
<button class="btn btn-default" ng-disabled="Cannot_Allocate_Yet" ng-
click="Get_Sampling_Request_Details()" type="button">test</button>
</div>
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.name = 0;
$scope.Get_Sampling_Request_Details = function () {
console.log("$scope.aabbcc: " + $scope.name) ;
}
}
AngularJS controllers control the data. The scope is the binding part between the HTML (view) and the JavaScript (controller). You must define the ng-model inside a ng-controller within which its scope lies. Try this out.
<div ng-controller="myCtrl">
<div class="input-group" style="width:100px">
<input type="number"
class="form-control"
id="Sampling_Request_for_Current_Sampling_INPUT"
ng-model="aabbcc"
style="width:125px;text-align:center">
<span class="input-group-btn">
<button class="btn btn-default" ng-disabled="Cannot_Allocate_Yet" ng-click="Get_Sampling_Request_Details()" type="button">{{All_Labels.Common.Display}}</button>
</span>
</div>
</div>
<script>
var app = angular.module('Myapp', []);
app.controller('myCtrl', function($scope) {
$scope.Get_Sampling_Request_Details = function () {
console.log("$scope.aabbcc: " + $scope.aabbcc) ;
}
});
</script>
Declare an empty object in your controller section .
eg: $scope.obj = {};
And use like ng-model="obj.key_name" in your html. It will work.
I create a form dynamically in the view by iterating through an object that has the different questions to be asked to the user. One of the attributes of every question is formFieldName which is a a random string I use to give each form field a different name.
<form name="includedForm.newRequestForm" class="form-horizontal" role="form" novalidate>
<div ng-if="message.question.attributes.structure.type == 'object'">
<div ng-repeat="(index,objField) in message.question.attributes.structure.properties">
<div ng-if="objField.type == 'array'" class="form-group" show-errors>
<label for="{{objField.formFieldName}}" class="control-label col-sm-6">{{objField.title}}
<br /><i><small>{{objField.description}}</small></i></label>
<div class="col-sm-6">
<select class="form-control" name="{{objField.formFieldName}}" multiple ng-model="objField.userValue" ng-required="objField.required">
<option ng-repeat="option in objField.items.enum" value="{{option}}">{{option}}</option>
</select>
</div>
</div>
<div ng-if="objField.type == 'boolean'" class="form-group" show-errors>
<label for="{{objField.formFieldName}}" class="control-label col-sm-6">{{objField.title}}</label>
<div class="col-sm-6">
<input class="form-control" name="{{objField.formFieldName}}" ng-model="objField.userValue" type="checkbox" ng-value="option" ng-checked="message.question.attributes" />
</div>
</div>
</div>
</div>
<div class="col-sm-12">
<button ng-click="markAsDone(message)" class="btn btn-primary">Done</button>
</div>
<form>
In the controller I'm able to get the formFieldName attribute but I can't figure out how to use it to do the validation.
var MarkAsDone = function(message) {
$scope.includedForm = {};
var formField = message.question.attributes.formFieldName;
if ($scope.includedForm.newRequestForm.{{formField}}.$valid){
//submit the form
}
}
to answer you question:
first, {{}} is === $scope so you don't use that anywhere other than HTML. You use $scope in your JS and {{}} in HTML which creates a pipe (2-way binding) so that $scope.variable.property has bidirectional binding to {{variable.property }} in HTML.
$scope.includeForm.email === {{ includeForm.email }} === ng-model="includeForm.email" === ng-bind="includeForm.email"
if you set anyone of those all are set so if you set $scope it will show up in HTML and obviously as user input gets captured it is already in $scope ... all connected
when attempting to get the value from HTML back into JS you would need create and set a $scope i.e so if you create $scope.dataModel.dataProperty and use that in ng-model=dataModel.dataProperty (example) you again have two way binding ... you don't need to do anything as angular is taking care of the data pipeline. So if you want to extract the value to var, which is probably a waste as the $scope is already set as soon as the user checks the box
var formField = $scope.dataModel.dataProperty;
// but like I said no need as $scope.dataModel.dataProperty; is your var
In JS if you want to use a dynamic property as an object property key you would place the dynamic value in [] e.g.
$scope.variable[dynamicProperty].method;
// you can set a static property as a key with dot notation i.e.
$scope.variable.staticProperty = val;
Hope that helps
I have the following code:
<div class="col-md-10" data-ng-controller="type-controller">
<div class="btn-group" data-toggle="buttons">
<label class="btn btn-success" ng-model="typeId" data-btn-radio="'1'">
Option 1
</label>
<label class="btn btn-success" ng-model="typeId" data-btn-radio="'2'">
Option 2
</label>
</div>
<input data-ng-model="typeId" name="typeId" type="hidden" data-start="2" />
</div>
My type-controller is empty so I'm omitting it - but I want to get the value of the attribute data-start from the last input inside the type-controller.
I'm not using jQuery.
IF the attribute data-start is significant because it is being used by some other 3rd party library, then you might consider simply using ng-init when you create this on the server:
<input data-ng-model="typeId" name="typeId" type="hidden" data-start="2"
ng-init='start = 2' />
This will essentially run any code you need, and doesn't involve you having to parse out data attributes from the DOM.
You could write a pretty trivial directive to pull in the value and publish using an expression. This will essentially accomplish the same thing, but is more difficult in my opinion:
angular.module('data-pluck', [])
.controller('fooController', function() {
this.name = 'Foo Controller';
})
.directive('pluckData', ['$parse',
function($parse) {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
var expression = function() {};
expression.assign = function() {};
scope.$watch(attrs.placeData, function() {
expression = $parse(attrs.placeData);
});
scope.$watch(attrs.pluckData, function() {
expression.assign(scope, attrs[attrs.pluckData]);
});
}
};
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='data-pluck' ng-controller='fooController as ctrl'>
<h1>{{ctrl.name}}</h1>
<div data-my-val="I'm value one" pluck-data='myVal' place-data='ctrl.valueOne'>
<p>I'm a regular old <code><p></code> tag</p>
<input type='hidden' data-my-val="I'm the second value" pluck-data='myVal' place-data='ctrl.valueTwo' />
</div>
<h3>These Values Populated Dynamically</h3>
<ul>
<li>ctrl.valueOne = {{ctrl.valueOne}}</li>
<li>ctrl.valueTwo = {{ctrl.valueTwo}}</li>
</ul>
</div>
Angular comes with jqLite built in, which still has the attr() function. But it's not the Angular "way" to be manually fiddling around in the DOM from a controller. Your scope should be the interface between them.
I'm curious as to why you have a value in an attribute in your UI that isn't defined first in your model / scope? How does this value get changed? Is there a reason why you can't set it in the controller:
$scope.start = 2;
and then:
<input data-ng-model="typeId" name="typeId" type="hidden" data-start="{{start}}" />
Can you explain a little about what data-start is meant to do?
I have a register function in my controller:
$scope.register = function() {
User.register($scope.user)
.success(function(data) {
if(data.success) {
$scope.stage = false;
} else {
$scope.message = true;
}
});
}
I then have this HTML:
<div class="form-group" ng-class="{ hidden: stage }">
<label for="token">Confirmation Token</label>
<input type="text" class="form-control" placeholder="Enter the token sent to your phone" ng-model="user.token" required>
</div>
Typically in jQuery I'd update the DOM by removing the class hidden if data.success. Here I've used ng-class to conditionally apply or remove a class, but it seems it's not working.
I want the class to be there by default, and then want it to be removed if data.success
What am I doing wrong here?
You need to set stage to some truthy value in your controller if you want the class to be applied.
$scope.stage = true;
User.register($scope.user)
...
And if all you're aiming to do it show/hide the element, you could use ng-show or ng-hide instead of ng-class (but you'd still need to set stage to true):
<div class="form-group" ng-show="stage">
Try something like this:
<div class="form-group" ng-class="{true: 'hidden'}[stage]">
I would like to find a way to insert HTML (which is optimalized for the controller) into alert div. However I couldn't find a way to do it...
<script type="text/ng-include" id="login.html">
<form data-select="exeption" class="loginBox shadowed" onclick="event.stopPropagation();" novalidate name="login">
<h2>Login alert</h2>
<!--inputs and such, they need to be controlled by the controller-->
</form>
</script>
<script type="text/ng-include" id="bug.html">
<form data-select="exeption" class="bugBox shadowed" onclick="event.stopPropagation();" novalidate name="report">
<h2>Bug report</h2>
<!--inputs and such, they need to be controlled by the controller-->
</form>
</script>
This two templates should be evoked by the JS itself or by user. Those templates should get into this div, but I can't use innerHTML since in templates are some ng-models and such things...
<div id="alert" data-ng-click="empty()" data-ng-controller="alert" role="navigation"></div>
Usually what I do is use ng-if / ng-show .
I'm not sure I understood your request correctly, so I'll write a little example; let's say you have a simple login form:
<form>
<label>
username:
<input name="username" type="text" ng-model="username"/>
</label>
<label>
password:
<input name="password" type="password" ng-model="password"/>
</label>
<button type="submit" ng-click="login()">login</button>
<div class="message" ng-if="message">
</div>
</form>
Inside the controller:
$scope.username = '';
$scope.password = '';
$scope.message = '';
$scope.login = function() {
// login example function with ajax request and success/error promises
myLogin($scope.username, $scope.password)
.success(function() {
$scope.message = 'Logged in!';
})
.error(function(errorMessage) {
$scope.message = errorMessage;
})
}
This way your div is empty when $scope.message is empty and you can show it automatically just giving $scope.message a value.
If you need to have an ng-include, simplest thing you could do is to use it inside a div that you show when you need it:
<div ng-if="showMessage">
<div ng-include="template.html"/>
</div>
UPDATE: following my last example, if you wanted to include a different type of message for every situation, you could use multiple ngIf, including different template; example:
<div ng-if="showMessage">
<div ng-if="message.type == 'alert'" ng-include="'alert.html'"/>
<div ng-if="message.type == 'info'" ng-include="'info.html'"/>
<div ng-if="message.type == 'warning'" ng-include="'warning.html'"/>
<div ng-if="message.type == 'error'" ng-include="'error.html'"/>
</div>
This way you can also do an ngInclude for a login form, or another kind of popup.
UPDATE 2: same last example, but with another solution:
<div ng-if="showMessage">
<div ng-include="templatePath"/>
</div>
then you can give in the controller the whole path to the partial:
$scope.templatePath = 'alert.html';