This question already has answers here:
What are the nuances of scope prototypal / prototypical inheritance in AngularJS?
(3 answers)
Closed 7 years ago.
I have a problem when i try to fragment my html with ng-include:
This is what my index.html page looks like when it works (prix=price, TVA=tax):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link type="text/css" rel="stylesheet" href="style.css" />
<title> TVA </title>
</head>
<body>
<div>
<div ng-app="app" ng-controller="appCtrl">
<input ng-model="tva" placeholder="TVA" /><br />
<input ng-model="prix" placeholder="Prix" />
<select ng-model="taxe">
<option>HT</option>
<option>TTC</option>
</select>
<button id="btn" ng-click="calcul()">Calculer</button>
<p>{{ total }}</p>
</div>
</div>
<script src="angular.min.js"></script>
<script src="script.js"></script>
</body>
</html>
The script.js :
app = angular.module('app', []);
app.controller('appCtrl', ['$scope', function ($scope) {
$scope.calcul = function() {
if ($scope.taxe == "TTC") {
$scope.total = parseInt($scope.prix) + $scope.prix * $scope.tva /100;
} else if($scope.taxe == "HT") {
$scope.total = 1/(1+$scope.tva/100)*$scope.prix;
}
};
}]);
So this works, the result is an number (the price with or without tax).
When I use the ng-include like this:
<div>
<div ng-app="app" ng-controller="appCtrl">
<div ng-include="'tva.html'"></div>
<input ng-model="prix" placeholder="Prix" />
<select ng-model="taxe">
<option>HT</option>
<option>TTC</option>
</select>
<button id="btn" ng-click="calcul()">Calculer</button>
<p>{{ total }}</p>
</div>
</div>
I only tried to replace the first input with a new HTML page.
The tva.html :
<input ng-model="tva" placeholder="TVA" /><br />
Now the results show "NaN" (I put those codes on a server so that I can check online). Why is this?
#Josh Beam Answered & explained ng-include creates a child scope on creating the DOM. I'd suggest you to use dot rule in angular that will follow prototypal inheritance on that object and you object value will access in child scope.
Now your object structure will changed to $scope.model={}; and this model will have all the input values. like all will become like model.prix, model.taxe & model.tva so that the prototypal inheritance will follow.
Markup
<div ng-app="app" ng-controller="appCtrl">
<div ng-include="'tva.html'"></div>
<br />
<input ng-model="model.prix" placeholder="Prix" />
<select ng-model="model.taxe">
<option>HT</option>
<option>TTC</option>
</select>
<button id="btn" ng-click="calcul()">Calculer</button>
<p>{{ total }}</p>
</div>
Code
app.controller('appCtrl', ['$scope', function ($scope) {
$scope.model = {};
$scope.calcul = function() {
if ($scope.model.taxe == "TTC") {
$scope.total = parseInt($scope.model.prix) + $scope.model.prix * $scope.model.tva /100;
} else if($scope.model.taxe == "HT") {
$scope.total = 1/(1+$scope.model.tva/100)*$scope.model.prix;
}
};
}]);
tva.html
<input ng-model="model.tva" placeholder="TVA" /><br />
Demo Plunkr
Short answer: don't use ng-include in this instance.
Long answer: ng-include creates a new child scope, so ng-model inside the ng-include isn't appCtrl's TVA. I don't see a reason here to use ng-include anyway, your code is fine without it.
So basically you're getting NaN (not a number) because $scope.TVA is never set when using the ng-include... you're attempting to multiply an undefined variable by another number, which returns NaN:
The reason for that is the ng-include creates a new scope under the scope when the HTML was included, but you can access to the parent scope by specifying $parent
<input ng-model="$parent.tva" placeholder="TVA" /><br />
A better approach is give an alias to your controller, so it will be clear semantically to children controllers accessing to a specific parent.
<div ng-app="app" ng-controller="appCtrl as vmMain">
<div ng-include="'tva.html'"></div>
... and in the other file:
<input ng-model="vmMain.tva" placeholder="TVA" /><br />
Related
I'm using angularJS to do some custom filter work, but it failed to display model information at the first stage.
<html lang="en" data-ng-app="myApp">
<Head>
<title>Custom filter</title>
<meta charset="utf-8">
</head>
<body>
<div data-ng-init="varNum=0">
<p>
<label for="number">Enter number from 1 to 99:</label>
<input type="number" data-ng-model="varNum" id="number"/>
</p>
<p>Your number: {{ varNum }}</p>
</div>
<script src="js/angular.min.js"></script>
<script src="js/appromannumber.js"></script>
</body>
</html>
appromannumber.js
var app = angular.module("myApp", []);
app.filter("myFilter", function (){
return function(myNum) {
var formatedNumber = "";
switch(myNum) {
0:formatedNumber="zero";break;
return formatedNumber;
}
});
But if I remove the value of ng-app, like data-ng-app = "", it will start to display the varNum. I have no idea why this happen.
Should not work angular without bootstrap module means without ng-app="moduleName". I suspect that you miss something else and I mentioned bellow some problem in your code that may will help you
in your filter you missed
case in switch statement. need case 0: instead of 0:...
return formatedNumber; this statement is unreachable. should use after switch statement
you can try like:
app.filter("myFilter", function (){
return function(myNum) {
var formatedNumber = "";
switch(myNum) {
case 0:formatedNumber="zero";break;
case 1:formatedNumber="One";break;
}
return formatedNumber;
};
});
and in html:
<div data-ng-init="varNum=0">
<p>
<label for="number">Enter number from 1 to 99:</label>
<input type="number" data-ng-model="varNum" id="number"/>
</p>
<p>Your number: {{ varNum | myFilter }}</p> // shown filtered value
</div>
I am facing a strange problem with the below code..
whenever I remove the ng-controller="page" from the body tag, the expressions start getting evaluated. But on applying this controller on body tag, the expressions tend to get printed as text rather than being evaluated.
Below is my relevant code (Snippet):
<html ng-app="app">
<head>
<!-- links removed for brevity -->
<script>
var app = angular.module('app',[]);
app.controller('page',function($scope){
$scope.segment.name = 'asdf';
});
</script>
</head>
<body ng-controller="page" style="padding:0px;">
<!-- additional markup removed for brevity -->
<form class="navbar-form navbar-right" role="search">
<div class="form-group">
<input type="text" class="form-control" placeholder="Enter Portal ID" ng-model="page.segment.name"/>
</div>
<button class="btn btn-default">Search {{page.segment.name}}</button>
</form>
</body>
</html>
I am possibly making some blunder in the above code as the below code which I wrote as proof of concept works well.
POC code (Snippet):
<html ng-app="app">
<head>
<!-- links removed for brevity -->
</head>
<body ng-controller="page">
<a>Name : {{page.segment.name}}</a>
<input type = "text" ng-model="page.segment.name"/>
</body>
<!-- links removed for brevity -->
<script>
var app = angular.module('app',[]);
app.controller('page',['$scope',function($scope){}]);
</script>
</html>
Kindly help
Thanks in advance..
You are probably getting an error in the console. I would guess it's something similar to "Cannot set property 'name' of undefined." What you are doing here is not valid:
$scope.segment.name = 'asdf';
You need to either do this:
$scope.segment = {};
$scope.segment.name = 'asdf';
Or this:
$scope.segment = { name: 'asdf' };
You have to create the segment object explicitly before you attempt to set properties on it.
I have an AngularJS app that I manually bootstrap at time 't'. At time 't + 1', I would like to show an HTML element that has no ng-controller attached. I would like to dynamically add a ng-controller to this element so it can communicate with my javascript code.
How can I do that?
PS I tried to dynamically add the ng-controller attribute to the element but it doesn't work.
To do that you need to compile elements.
HTML
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.5/angular.min.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.2/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="main.css" rel="stylesheet" type="text/css" />
<script src="main.js"></script>
<meta charset=utf-8 />
<title>Angular JS</title>
</head>
<body ng-controller="parentCtrl">
<button ng-click="setCtrl2()">Set Controller</button>
<div id="placeholder">
<span></span>
<select>
<option></option>
</select>
<span class="input-append">
<input id="add" type="text" placeholder="Another one ?" ng-model="addName" />
<input type="submit" class="btn btn-primary" ng-click="addRow()" value="+ add" />
</span>
</div>
</body>
</html>
Javascript
angular.module('app', []);
angular.module('app').controller('ctrl', function($scope) {
$scope.rows = ['Paul','John','Lucie'];
$scope.name = 'Jack';
$scope.addRow = function(){
$scope.rows.push($scope.addName);
$scope.addName = "";
console.log($scope.rows);
};
})
.controller('parentCtrl', function($scope) {
$scope.setCtrl2 = setCtrl;
});
function setCtrl() {
var elem = document.getElementById('placeholder');
elem.setAttribute('ng-controller', 'ctrl');
var eSpan = elem.children[0];
var eSelect = elem.children[1].children[0];
eSpan.setAttribute('ng-bind', 'name');
eSelect.setAttribute('ng-repeat', 'row in rows');
eSelect.setAttribute('value', '{{ row }}');
eSelect.setAttribute('ng-bind', 'row');
var injector = angular.element(elem).injector();
var compile = injector.get('$compile');
var rootScope = injector.get('$rootScope');
var result = compile(elem)(rootScope);
// When outside of AngularJS you need to call digest
// rootScope.$digest();
}
See: http://codepen.io/skarllot/pen/LVKpgd
You don't mention whether you've looked at previously asked questions. I found two which look like they could address the question you've asked:
Loading an AngularJS controller dynamically
How to bind an AngularJS controller to dynamically added HTML?
I have a simple view with an input text field in which the user enter his name and a controller must retrieve that value an assign to employeeDescription variable. The problem is that the ng-model value (from the input) doesn't come to the controller, I just tried using $watch like Radim Köhler explains Cannot get model value in controller method in angular js but doesn't work. I just think it must be simple.
Also a just try by retrieving the name variable (ng-model) from the $scope, like $scope.employeeDescription = $scope.name; but doesn't retrieve value and the Google chrome console doesn't give me any output about that. Any solution?
index.html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
</head>
<body ng-app='angularApp'>
<div ng-controller='nameController'>
<div>
Name <input type="text" ng-model='name' />
</div>
Welcome {{employeeDescription}}
</div>
<script type="text/javascript" src="angular.min.js"></script>
<script type="text/javascript" src="app.js"></script>
</body>
</html>
app.js
(function(angular) {
var myAppModule = angular.module('angularApp', []);
myAppModule.controller('nameController', function($scope) {
$scope.employeeDescription = name;
});
})(window.angular);
Your code should fail, cause the 'name' variable in the controller is never defined. You have two variables defined in your code: $scope.employeeDescription and $scope.name (defined in the ng-model of the input). Note that '$scope.name' is being defined, not 'name'.
My suggestion is to leave only one variable:
<div>
Name <input type="text" ng-model='employeeDescription' />
</div>
myAppModule.controller('nameController', function($scope) {
$scope.$watch('employeeDescription', function() {
console.log($scope.employeeDescription);
});
});
I have a simple two-way binding setup with angular, and I added a plain javascript function that updates the value based off of the "alt" tag of an image a user clicks on. The problem is that when I hit save, the data doesn't update until I click inside the textbox and add a space. What's the best way to get around this?
http://plnkr.co/edit/j6tPYYUqvRyvfs32mcrW?p=preview
angular.module('copyExample', [])
.controller('ExampleController', ['$scope',
function($scope) {
$scope.master = {};
$scope.update = function(user) {
// Example with 1 argument
$scope.master = angular.copy(user);
};
$scope.reset = function() {
// Example with 2 arguments
angular.copy($scope.master, $scope.user);
};
$scope.reset();
}
]);
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"></script>
</head>
<body ng-app="copyExample">
<div ng-controller="ExampleController">
<form novalidate class="simple-form">
Name:
<input type="text" ng-model="user.name" id="name" />
<br />
<img src="http://placehold.it/100&text=John" onclick="changeText(alt)" alt="John" />
<br />
<button ng-click="reset()">RESET</button>
<button ng-click="update(user)">SAVE</button>
</form>
<pre>form = {{user | json}}</pre>
<pre>master = {{master | json}}</pre>
</div>
<script>
function changeText(value) {
document.getElementById('name').value = value
}
</script>
</body>
</html>
working fiddle - http://jsfiddle.net/lwalden/b2p7pu7g/
If you are already using Angular then don't write a plain vanilla javascript function for the image click event - use Angular.
Also it's recommended not to use the alt attribute in this way. You could use a data- attribute instead.
Additional attributes within a tag to pass values to a function