AngularJS Controller not working in nested Controller - javascript

Got a questions regarding the select option value, i can get the value as the select options changed, but i am not able to get the value of the select options thru the search button, it will just give a value undefined. So where is the problem?
index.html
<div ng-controller="MatIncListCtrl">
<button class="fluid labeled icon blue ui button top attached"><i class="ellipsis vertical icon"></i>Toggle Filters Pane</button>
<div class="ui attached segment" uib-collapse="isCollapsed">
<form role="form" class="ui form">
<div class="fields">
<div class="twelve wide field" ng-controller="DistinctSupplierCtrl">
<label>Supplier</label>
<select ng-model="Supplier" class="ui fluid dropdown" ng-options="x.supp_no as x.supp for x in data" ng-change="selectAction()">
<option></option>
</select>
</div>
</div>
</form>
<br />
<button type="button" class="ui orange fluid labeled icon button" tabindex="0" ng-click="FindMatInc()"><i class="search icon"></i>Search</button>
</div>
</div>
controller.js
.controller('DistinctSupplierCtrl', function($scope, $http) {
$scope.selectAction = function() {
console.log($scope.Supplier);
};
var xhr = $http({
method: 'post',
url: 'http://localhost/api/list-distinct-supp.php'
});
xhr.success(function(data){
$scope.data = data.data;
});
})
.controller('MatIncListCtrl', function ($scope, $http) {
$scope.FindMatInc = function (){
console.log($scope.Supplier);
}
});

If you want to access a value from a scope, you've got to make sure it's in that scope or in the scope of it's ancestors. Now your ng-model is declared in the child scope. If you want to access it from the parent scope, you'll need to declare it in the parent scope. That way when the model get changed, it changed in the parent scope and thus accessible in both scopes:
Working example:
angular.module('App', []);
angular.module('App').controller('ControllerParent', [
'$scope',
function ($scope) {
// Model value declared in parent scope
$scope.selected = {};
}
]);
angular.module('App').controller('ControllerChild', [
'$scope',
function ($scope) {
$scope.options = [{
id: 1,
name: 'Alpha'
}, {
id: 2,
name: 'Bravo'
}, {
id: 3,
name: 'Charlie'
}, {
id: 4,
name: 'Delta'
}];
}
]);
<!DOCTYPE html>
<html ng-app="App">
<head>
<script type="application/javascript" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.js"></script>
</head>
<body ng-controller="ControllerParent">
<div ng-controller="ControllerChild">
<select ng-model="selected.value" ng-options="option.name for option in options"></select>
ControllerSub: {{selected}}
</div>
ControllerMain: {{selected}}
</body>
</html>
Failing example:
angular.module('App', []);
angular.module('App').controller('ControllerParent', [
'$scope',
function ($scope) {}
]);
angular.module('App').controller('ControllerChild', [
'$scope',
function ($scope) {
// Model value declared in child scope
$scope.selected = {};
$scope.options = [{
id: 1,
name: 'Alpha'
}, {
id: 2,
name: 'Bravo'
}, {
id: 3,
name: 'Charlie'
}, {
id: 4,
name: 'Delta'
}];
}
]);
<!DOCTYPE html>
<html ng-app="App">
<head>
<script type="application/javascript" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.js"></script>
</head>
<body ng-controller="ControllerParent">
<div ng-controller="ControllerChild">
<select ng-model="selected.value" ng-options="option.name for option in options"></select>
ControllerSub: {{selected}}
</div>
ControllerMain: {{selected}}
</body>
</html>
Descendant scopes have access to the values of their ancestors. Ancestors don't have access to values of their descendants.

Another way to work on nested controllers using the controller as syntax.
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>AngularJS Tutorial</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.4/angular.min.js"></script>
<script>
angular.module('app', []);
angular.module('app').controller("MainController", function(){
var vm = this; //The vm in this case means viewmodel
vm.title = 'AngularJS Nested Controller Example';
});
angular.module('app').controller("SubController", function(){
var vm = this;
vm.title = 'Sub-heading';
});
</script>
</head>
<body ng-app='app' ng-controller='MainController as main'>
<div class='container'>
<h1>{{main.title}}</h1>
<div ng-controller='SubController as sub'>
<h2>{{sub.title}}</h2>
<p>If we were not using the <strong>ControllerAs</strong> syntax we would have a problem using title twice!</p>
</div>
</div>
</body>
</html>

Related

Angularjs and ui-grid - add event keypress in cell

First of all, I want to say that I am beginner with angularjs :D
My problem is:
I'm trying add the keypress event when user goes to edit the value in cell on angular ui-grid.
In the beginning it seems to work, but when I finish editing a cell and mute the focus the value disappears.
Here is the link to see the event running: https://plnkr.co/edit/vw8W6PqFt11nt4BDhWu9
And here is my code:
File: index.html
<!doctype html>
<html ng-app="app">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.13/angular.js"></script>
<script src="//cdn.rawgit.com/angular-ui/bower-ui-grid/v3.0.6/ui-grid.min.js"></script>
<link rel="stylesheet" href="//cdn.rawgit.com/angular-ui/bower-ui-grid/v3.0.6/ui-grid.min.css" type="text/css" />
<link rel="stylesheet" href="main.css" type="text/css">
</head>
<body>
<div ng-controller="MainCtrl">
<div id="grid1" ui-grid="gridOptions" ui-grid-edit class="grid"></div>
</div>
<script src="app.js"></script>
</body>
</html>
File: app.js
(function() {
var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);
app.controller('MainCtrl', ['$scope', '$http', function($scope, $http) {
$scope.gridOptions = {
columnDefs: [{
field: 'name'
}, {
field: 'amount',
name: 'Number'
}, {
field: 'someValue',
name: 'SomeValue',
editableCellTemplate: 'template-cell.html'
}]
};
$http.get('data.json')
.success(function(data) {
$scope.gridOptions.data = data;
});
}]);
app.directive('numbersOnly', function () {
return {
require: 'ngModel',
link: function (scope, element, attr, ngModelCtrl) {
function fromUser(text) {
if (text) {
var transformedInput = text.replace(/[^0-9]/, '');
if (transformedInput !== text) {
ngModelCtrl.$setViewValue(transformedInput);
ngModelCtrl.$render();
}
return transformedInput;
}
return undefined;
}
ngModelCtrl.$parsers.push(fromUser);
}
};
});
}());
File: cell-template.html
<div>
<form name="inputForm">
<input type="text"
ui-grid-editor
ng-model="someValue"
data="row.entity.someValue"
ng-class="'colt' + col.uid"
numbers-only />
</form>
</div>
I need this functionality with keypress event only. How do I update the model with the input field value ?
Thanks.
The problem is that your column value is not correctly bound to the ngModel in the cell template.
The correct value would be to use the MODEL_COL_FIELD which you can read more about in the wiki, look at section "Editable Cell Templates"
Update your cell-template.html to
<div>
<form name="inputForm">
<input type="text"
ui-grid-editor
ng-model="MODEL_COL_FIELD"
ng-class="'colt' + col.uid"
numbers-only />
</form>
</div>

Scope values aren't displayed when getting HTML from server

UPDATE
After doing many tests on my code I'm updating my previous question, as it's now clearer to me what's not working.
My HTML file is served when I browse to the / directory in my local
All the pages loads nicely except for the content of the $scope in my directives (see below).
I've tested loading the page directly (just clicked on the html file) and I can see the content.
I'm not sure where the problem is.
I've removed all un-necessary lines from the HTML file to give a better pictures of my code. the {{}} is just the templating engine language.
HTML
<DOCTYPE html>
<html ng-app="docsSimpleDirective">
<head>
<link rel="stylesheet" type="text/css" href="/css/text.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0- alpha.5/css/bootstrap.min.css" integrity="sha384- AysaV+vQoT3kOAXZkl02PThvDr8HYKPZhNT5h/CXfBThSRXQ6jW5DO2ekP5ViFdi" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.1.1.js" integrity="sha256-16cdPddA6VdVInumRGo6IbivbERE8p7CQR3HzTBuELA=" crossorigin="anonymous"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<script src="https://www.atlasestateagents.co.uk/javascript/tether.min.js"> </script><!-- Tether for Bootstrap -->
<script src="https://cdn.rawgit.com/twbs/bootstrap/v4-dev/dist/js/bootstrap.min.js"></script><!-- Bootstrap -->
</head>
<body >
<h3>Select some text </h3>
<div ng-controller="Controller">
{% for i in result %}
<div id={{i._id}} class="task" commentId = {{i._id}} get-popover- content>{{i.text}} </div>
<div id={{i._id}} class="task" commentId = {{i._id}} my-customer="customer">{{i.text}} </div>
<br/>
{% endfor %}
</div>
<script>
(function(angular) {
'use strict';
angular.module('docsSimpleDirective', [])
.controller('Controller', ['$scope', function($scope) {
$scope.customer = {
name: 'Naomi',
address: '1600 Amphitheatre'
};
}])
.directive('myCustomer', function() {
return {
scope: {
myCustomer: '='
},
template: 'Name: {{myCustomer.name}} Address: {{myCustomer.address}}'
};
});
})(window.angular);
</script>
</body>
</html>
You can create an isolated scope to the directive as below with the same name as a directive name,
scope: {
myCustomer: '='
}
and link the controller's $scope.customer to this isolated scope as below,
<div ... my-customer="customer"></div>
And change your template to access the same like this,
template: 'Name: {{myCustomer.name}} Address: {{myCustomer.address}}'
Working sample:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body>
<h3>Select some text </h3>
<div ng-controller="Controller">
<div id="test1" class="task" commentId="test1" get-popover-content>{{i.text}} </div>
<div id="test2" class="task" commentId="test2" my-customer="customer">{{i.text}} </div>
<br/>
</div>
<script>
(function(angular) {
'use strict';
angular.module('docsSimpleDirective', [])
.controller('Controller', ['$scope', function($scope) {
$scope.customer = {
name: 'Naomi',
address: '1600 Amphitheatre'
};
}])
.directive('myCustomer', function() {
return {
scope: {
myCustomer: '='
},
template: 'Name: {{myCustomer.name}} Address: {{myCustomer.address}}'
};
});
angular.bootstrap(document, ['docsSimpleDirective']);
})(window.angular);
</script>
</body>
You have to use scope: { .... } inside directive to access your controller scope
Controller
(function(angular) {
'use strict';
angular.module('docsSimpleDirective', [])
.controller('Controller', ['$scope', function($scope) {
$scope.customer = {
name: 'Naomi',
address: '1600 Amphitheatre'
};
}])
HTML
// use this directive and pass customer to the directive scope
<my-customer customer="customer"></my-customer>
Directive
.directive('myCustomer', function() {
return {
scope: {
customer: '=customer'
}
template: 'Name: {{customer.name}} Address: {{customer.address}}'
};
});
Surround with
{{% raw %}} ... {{% endraw %}}
This is probably a better pattern for what you're trying to achieve (note the comment for an API call for your customers in JSON format).
Calling for the data via API after the page has loaded will allow you to keep your HTML/CSS/JAVASCRIPT as totally static files (no templating engine etc) and decoupled from your data.
It will load faster and give you the option to host your web front-end entirely on something like a CDN (which frees up your API server to focus only on requests for data/ sessions stuff like that).
<DOCTYPE html>
<html ng-app="docsSimpleDirective">
<head>
<!-- <link rel="stylesheet" type="text/css" href="/css/text.css"> -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.5/css/bootstrap.min.css" integrity="sha384-AysaV+vQoT3kOAXZkl02PThvDr8HYKPZhNT5h/CXfBThSRXQ6jW5DO2ekP5ViFdi" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.1.1.js" integrity="sha256-16cdPddA6VdVInumRGo6IbivbERE8p7CQR3HzTBuELA=" crossorigin="anonymous"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<script src="https://www.atlasestateagents.co.uk/javascript/tether.min.js"> </script><!-- Tether for Bootstrap -->
<script src="https://cdn.rawgit.com/twbs/bootstrap/v4-dev/dist/js/bootstrap.min.js"></script><!-- Bootstrap -->
</head>
<body>
<h3>Select some text</h3>
<div ng-controller="Controller">
<div ng-repeat="customer in customers">
<!-- not sure what 'id' or 'text' values are, you should pass them in
via API if they are needed -->
<div id={{i._id}} class="task" commentId = {{i._id}} get-popover- content>{{i.text}} </div>
<div id={{i._id}} class="task" commentId = {{i._id}} my-customer="customer">{{i.text}} </div>
<br/>
</div >
</div>
<script>
(function(angular) {
'use strict';
angular.module('docsSimpleDirective', [])
.controller('Controller', ['$scope', function($scope) {
// make a request to api to get customers in JSON format
// assign result to scope.customers
$scope.customers= [
{
name: 'Naomi',
address: '1600 Amphitheatre'
},
{
name: 'Amir',
address: '58 W 54th st'
}
];
}])
.directive('myCustomer', function() {
return {
scope: {
myCustomer: '='
},
template: 'Name: {{myCustomer.name}} Address: {{myCustomer.address}}'
};
}); // directive
})(window.angular);
</script>
</body>
</html>
you can also mock a REST API server by making a request to a static file like this:
$http.get("./myFakeAPI.json").then(function(response){
$scope.customers = response.data.customers;
});
where the contents of the file 'myFakeAPI.json' is:
{
"customers":
[
{
name: 'Naomi',
address: '1600 Amphitheatre'
},
{
name: 'Amir',
address: '58 W 54th st'
}
]
}

Save Data from form on button click

How to save data from the form by clicking on the button?
I do not understand where the error is.
As planned, when you click on the data from the field stored in the variable "master"
For example I use this tutorial: http://www.w3schools.com/angular/angular_forms.asp
<!DOCTYPE html>
<html lang="en">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body> <div ng-app="myApp" ng-controller="formCtrl">
<form novalidate>
First Name:<br>
<input type="text" ng-model="firstName"><br>
<button ng-click="copyData()">Click Me!</button>
</form>
<p>form = {{user}}</p>
<p>master = {{master}}</p>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('formCtrl', function($scope) {
$scope.master = {uder.firstName};
$scope.reset = function() {
$scope.user = angular.copy($scope.master);
};
$scope.reset();
$scope.copyData=function(){
$scope.master1=angular.copy($scope.mas);
$scope.copyData();
}
});
</script>
</body>
</html>
First of all you have a typo error. Replace {uder.firstname} with {user.firstname}.
You should put some effort on understanding scopes and how you can use variables, that you declare on scopes.
You declare an input with ng-model="firstname", but on the controller you have a user object with the attribute firstname. You should change your form to:
<input type="text" ng-model="user.firstName"><br>
<button ng-click="reset()">RESET</button>
<button ng-click="copyData()">Click Me!</button>
and in your controller
app.controller('formCtrl', function($scope) {
$scope.user = { firstname:"", lastname:"" }; //init your user
$scope.master = user.firstname; //or user object itself, dont understand what exactly you would like to achieve
$scope.reset = function() {
$scope.user = $scope.master;
};
$scope.copyData=function(){ }//call your onclick event
//set the data, that you want directly here. Recursion will not work.
More information about scope and forms can definitely help you.
Firstly,There are some typos like $scope.mas and {uder.firstname}.
Inspite of that you are assigning a property to the $scope object using ng-model directive but in the controller you are trying to access it using an object called user which would be undefined at this point.Here is the change in your code
First Name:<br>
<input type="text" ng-model="user.firstName"><br>
<button ng-click="reset()">
RESET</button>
<button ng-click="copyData()">
Click Me!</button>
</form>
<p>
form = {{user}}</p>
<p>
master = {{master}}</p>
The controller would be like
$scope.reset = function() {
$scope.user = angular.copy($scope.master);
};
$scope.reset();
$scope.copyData = function () {
$scope.master = user.firstName;
$scope.master1=angular.copy($scope.master);
$scope.copyData();
};
Thanks to all!
A working version:
(function(angular) {
'use strict';
angular.module('scopeExample', [])
.controller('MyController', ['$scope', function($scope) {
$scope.username = 'World';
$scope.sayHello = function() {
$scope.greeting = 'Hello ' + $scope.username + '!';
};
}]);
})(window.angular);
-<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Angular JS</title>
<link rel="stylesheet" type="text/css" href="style.css">
<script src="angular.min.js"></script>
<script src="weather 2.js"></script>
</head>
<body ng-app="scopeExample">
<div ng-controller="MyController">
Your name:
<input type="text" ng-model="username">
<button ng-click='sayHello()'>greet</button>
<hr>
{{greeting}}
</div>
</body>
</html>

console.log for $scope in angular js

Why I'm not able to console output $scope values ? I'm trying to extract user assigned values from the pages and retrieve in controller. Eventually i would like to pass this to service so multiple controllers can access these data.
HTML
<!DOCTYPE html>
<html lang="en-us" ng-app="myApp">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta charset="UTF-8">
<link rel="stylesheet" href="css/bootstrap.min.css" />
<!-- CDN lib files -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular-animate.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/1.1.0/ui-bootstrap-tpls.min.js"></script>
<!-- custom angular script -->
<script src="js/app.js"></script>
</head>
<body>
<div class="container">
<div ng-controller="mainController">
<h1>Hello world!</h1>
<label> Please enter something</label>
<input textarea ng-model="name"></input>
<h4> This is what you entered : {{ name }} </h4>
<h4 style=color:red> now filtering: {{ lower() }}</h4>
</div>
</div>
</body>
</html>
APP.JS
var myApp = angular.module('myApp', []);
myApp.controller('mainController', ['$scope', '$filter', function($scope, $filter) {
$scope.name = 'Test ';
$scope.lower = function(){
return $filter('lowercase')($scope.name);
}
$scope.name = $scope.lower();
console.log($scope.name);
console.log($scope.lower());
}]);
Console will output values upon initializing but not after user make changes.
You need to watch the scope variable:
$scope.$watch('name', function() {
console.log($scope.name);
});
More information: https://stackoverflow.com/a/15113029/5787736
Just a more "functional" version. Everyone is right, you are logging the observable, not what was observed. What you want is for console.log to be called on each change to $scope, not called once (as you have it now).
$scope.$watch("name", console.log);
You're logging only from the constructor. If you want to log each time something changes, consider a watch:
$scope.$watch("name", function() {
console.log($scope.name);
}
Why would you expect a controller to be rerendered when a scope variable changes? You can use scope watchers or input event listeners to listen for changes.
Here's an example with a watcher:
var myApp = angular.module('myApp', []);
myApp.controller('mainController', ['$scope', '$filter', function($scope, $filter) {
$scope.name = 'Test ';
$scope.lower = function(){
return $filter('lowercase')($scope.name);
}
$scope.name = $scope.lower();
console.log($scope.name);
console.log($scope.lower());
$scope.$watch('name', function() {
console.log($scope.name);
console.log($scope.lower());
});
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" class="container">
<div ng-controller="mainController">
<h1>Hello world!</h1>
<label>Please enter something</label>
<input textarea ng-model="name" />
<h4> This is what you entered : {{ name }} </h4>
<h4 style=color:red> now filtering: {{ lower() }}</h4>
</div>
</div>

Angular ng-repeat for a select, setting one option as selected using $rootScope variable

I have the following select:
<select class="form-control"
onchange="User_Changed_Language()"
id="HeaderLanguageSelection"
style="cursor:pointer;width:100%;height:30px;margin:0;padding:0"
title="{{Labels.Change_Language_Tooltip}}">
<option ng-repeat="One_Language in Languages_List"
value="{{One_Language.Code}}"
ng-selected="One_Language.Code == current_Language">
{{One_Language.Name}}
</option>
</select>
Now, current_Language is a $rootScope variable with a value (e.g. "EN"). I want the select element to display the selected value instead of the very first. What am I doing wrong?
One more note: I know that I could use ng-click, but I don't think this is the source of the issue.
Thanks.
Check this snippet:
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope, $rootScope) {
$scope.Labels = {Change_Language_Tooltip: "change lang"};
$scope.Languages_List = [
{ name: 'English', Code: 'en' },
{ name: 'Espanol', Code: 'es' },
{ name: 'Italian', Code: 'it' }];
$rootScope.current_Language = $scope.Languages_List[1];
});
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<script src="https://code.angularjs.org/1.3.15/angular.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>selected item is : {{current_Language}}</p>
<select class="form-control"
onchange="User_Changed_Language()"
id="HeaderLanguageSelection"
style="cursor:pointer;width:100%;height:30px;margin:0;padding:0"
title="{{Labels.Change_Language_Tooltip}}"
ng-options="item.name for item in Languages_List track by item.Code"
ng-model="current_Language">
</select>
</body>
</html>
PS: the selected item (default or initial) must be one element of the items used in the ngOptions list

Categories

Resources