Dynamic property on JavaScript object getting null - javascript

I'm trying to set the dynamic property on a javascript object using the ng-model. But I'm unable to create it as I always get null for that property. I have different ways to copy the value from the variable self.username to self.params javascript object in the below code.
Please see this plnkr
index.html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<link rel="stylesheet" href="style.css">
<script src="//code.angularjs.org/1.2.26/angular.js"></script>
<script src="https://code.angularjs.org/1.2.26/angular-route.min.js">
</script>
<script src="app.js"></script>
<script src="routes.js"></script>
</head>
<body>
Carriers
<div class="mainContainer" ng-view></div>
</body>
</html>
routes.js
myApp.config(function($routeProvider) {
$routeProvider
.when('/carriers', {
templateUrl: 'carriers.html',
controller: 'MainCtrl',
controllerAs: 'mainCtrl'
})
.otherwise({
redirectTo: '/'
});
});
Carriers.html
<input type="text" placeholder="username" ng-model="mainCtrl.username" />
<button ng-click="mainCtrl.login()">Login</button>
app.js
var myApp = angular.module('myApp', ['ngRoute']);
myApp.controller('MainCtrl', function() {
var self = this;
self.username = '';
self.login = login;
self.params = {
username: self.username //doesnt work
};
//self.params.username=angular.copy(self.username); //doesnt work
//self.params['username']=self.username; //doesnt work
function login() {
// alert(self.username);
console.dir(self.username); // works
console.dir(self.params); // username:'' getting empty string for username property
}
});

The value does not update because you created a new object and set the value of self.params.username to the value of self.params. self.params.username does not reference self.params it was just set from the value when the object was created.
If you want to bind self.params.username to the input then you can change your input model to:
<input type="text" placeholder="username" ng-model="mainCtrl.params.username" />
Another alternative is to watch self.username and set the value of self.params.username to the new value using $watch
// watch mainCtrl.username for any changes
$scope.$watch('mainCtrl.username', function(newValue, oldValue) {
// set self.params.username from the new value
self.params.username = newValue;
});

Related

modalInstance is undefined in Angular js

ModalInstance data is getting NULL in importing controller.
I have changed modelInstance name also.But dint work out.
here am adding my code,
SaveController.js
scope.open = function (_data) { //data is present
var modalInstanceData = modal.open({
controller: "PopUpController",
templateUrl: 'myModalContent.html',
resolve: {
data: function()
{
return _data; // values are present here
}
}
});
};
PopUpController.js
angular.module('user').controller('PopUpController',
['$scope','$state','$uibModalInstance',
function(scope,state,modalInstanceData,data) {
data={};
scope.data = data;
farmBid.produceValue = scope.data.produceId; //value is present here
}])
Html
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-body">
<input type="text" name="produceValue" ng-model="farmBid.produceValue" />
<!-- But here its not prefilling the data-->
<input type="submit" ng-click="generate(farmBid)">
</div>
</script>
Modal data values are not being visible in HTML page
Please help
You should pass the parameters in right order and should match, you are missing 'data'
angular.module('user').controller('PopUpController',
['$scope','$state','$uibModalInstance','data',
function(scope,state,modalInstanceData,data) {

How to access controller scope from dynamically created directive

Basically I am trying to access controller scope property from directive's controller function. I am doing it through $parent property. It works fine for static directive but not for dynamically created directive.
please have a look on my plunker
Dynamic Directive
In a plunker, when I click on folder with Id = 1. all goes good and folder path shows as "1 path". Same goes for folder with Id = 2.
But it does not work for dynamically appended folder with Id = n
I am somewhat new to angular. Any help would be much appreciated.
Updated Answer
In light of the latest requirement:
I am trying to call the directive function (i.e updateMap) from
controller.
You can use a Service to share variables between Controllers and Isolated Directives. In the example below, the Service holds the function that will be executed. Each directive when clicked will set the Service's function to it's own updateMap() function. Then the Controller in onFolderPathClicked() calls the Services executeFunction() function, which runs the previously set function.
script.js:
var module = angular.module('testApp', []);
module.service('updateMapService', function(){
var updateMapFunction = null;
this.executeFunction = function(){
updateMapFunction();
};
this.setFunction = function(fn){
updateMapFunction = fn;
};
});
module.controller('crtl', function($scope, updateMapService) {
$scope.onFolderPathClicked = function(){
updateMapService.executeFunction();
};
});
module.directive('folder', function($compile) {
return {
restrict: 'E',
scope: {
id: '#',
folderPath: "="
},
template: '<p ng-click="onFolderClicked()">{{id}}</p>',
controller: function($scope, $element, updateMapService) {
$scope.onFolderClicked = function(){
updateMapService.setFunction(updateMap);
addFolder();
};
var addFolder = function() {
$scope.folderPath = $scope.id + ":click here for calling update map";
var el = $compile('<folder id="n" folder-path="folderPath"></folder>')($scope);
$element.parent().append(el);
};
var updateMap = function() {
alert('inside updateMap()..' + $scope.id);
}
}
}
});
index.html:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body>
<div ng-app="testApp" ng-controller="crtl">
<div>FolderPath : <a ng-click="onFolderPathClicked()">{{ folderPath }}</a> </div>
<folder id="1" folder-path="folderPath"></folder>
<folder id="2" folder-path="folderPath"></folder>
</div>
</html>
You could also move folder-path into a Service to save from passing it in as an attribute. The code smell being that passing it in as an attribute means doing so twice, whereas in a Service it means setting it and getting it once (code reuse).

How to access directive's controller $scope properties inside controller

I have to access value from directive's controller inside my controller.
<div ng-controller="myCtrl">
<my-directive atr="xyz"></my-directive>
</div>
//here is my directive
app.directive('myDirective',function() {
return {
restrict : 'E',
replace : false,
scope :{
atr :'#'
},
controller : function($scope) {
console.log($scope.atr); //xyz
$scope.keyPoint ="this is what i want to access inside myCtrl";
}
}
});
//here is ctrl
app.controller('myCtrl',function($scope){
//how can I access keyPoint here
})
Isolating scope:
You Should use two-way binding for the keypoint to achieve this.
scope :{
atr :'#',
keyPoint: '='
},
What this will do is when ever you change the value in Directive, it reflects in your Controller, and vice-versa
// Instantiate the app, the 'myApp' parameter must
// match what is in ng-app
var myApp = angular.module('myApp', []);
// Create the controller, the 'ToddlerCtrl' parameter
// must match an ng-controller directive
myApp.directive('myDirective',function() {
return {
restrict : 'E',
replace : false,
scope :{
atr :'#',
keyPoint: '='
},
controller : function($scope) {
console.log($scope.atr); //xyz
$scope.keyPoint ="this is what i want to access inside myCtrl";
}
}
});
myApp.controller('myCtrl',function($scope,$timeout){
$timeout(function(){
alert($scope.keypoint)
},500)
})
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<script data-require="angular.js#1.2.7" data-semver="1.2.7" src="http://code.angularjs.org/1.2.7/angular.js"></script>
<link href="style.css" rel="stylesheet" />
<script src="script.js"></script>
</head>
<body>
<h1>Starter AngularJS app</h1>
<div ng-controller="myCtrl">
<my-directive atr="xyz" key-point="keypoint"></my-directive>
</div>
{{keypoint}}
</body>
</html>
Please run this snippet
Here is the fiddle
Without Isolating scope:
If you want to get the scope of the controller in the directive, dont Isolate the scope in the directive.
If you Isolate the scope, you cannot get controller's scope.
// Instantiate the app, the 'myApp' parameter must
// match what is in ng-app
var myApp = angular.module('myApp', []);
// Create the controller, the 'ToddlerCtrl' parameter
// must match an ng-controller directive
myApp.directive('myDirective',function() {
return {
restrict : 'E',
replace : false,
controller : function($scope) {
console.log($scope.atr); //xyz
$scope.keyPoint ="this is what i want to access inside myCtrl";
}
}
});
myApp.controller('myCtrl',function($scope,$timeout){
$scope.atr="xyz"
$timeout(function(){
alert($scope.keyPoint)
$scope.$apply();
},500)
})
<script data-require="angular.js#1.2.7" data-semver="1.2.7" src="http://code.angularjs.org/1.2.7/angular.js"></script>
<link href="style.css" rel="stylesheet" />
<script src="script.js"></script>
<body ng-app="myApp">
<h1>Starter AngularJS app</h1>
<div ng-controller="myCtrl">
<my-directive ></my-directive>
<h1>{{keyPoint}}</h1>
</div>
</body>
Fiddle for second snippet

Ways to declare Function in AngularJS Controller (controllerAs approach)

I use controller as approach instead of $scope. I have some problems with method calling from HTML. So, the question is that, how many ways exist in declare and call functions in this approach.
first: (If I want to do s.th. at first)
var vm= this ;
vm.dataOne=[];
function funcOne() {
myService.serviceFunc()
.then(function (response) {
vm.dataOne= response.data;
});
};
function activate() {
funcOne();
}
activate();
second: (If I want to initialize a variable based on a function returned value )
vm.dataTwo = function () {
doSomeThing();
}
Is there any way, too?
How should define a function in controller
which will be called from HTML, as
ng-click = "ctrl.dataTwo()";
Functions the way you've defined are private:
function functionOne() {
}; // Just function body, no need of semicolon
These are known as function declarations. Currently, they are only accessible within your controller.
To be able to call them, attach them to the controller so they become controller variables:
vm.functionOne = functionOne;
An advantage of this approach is that you can define functions after actually calling them, as opposed to how you do with $scope or $this. They are recognized via hoisting, and called.
About your initializing a returned value from a function, just call it:
vm.someVariable = someFunction();
Some references:
var functionName = function() {} vs function functionName() {}
Private Members in JavaScript
Angular Function Declarations, Function Expressions, and Readable Code
Angular Style Guide
First way using ng-controller="cntrl as vm" syntax:
<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script>
angular.module('MyApp', [])
.controller('MyCntrl', function($scope) {
var vm = this;
vm.name = 'Custom Directive';
});
</script>
<body>
<div ng-app="MyApp" ng-controller="MyCntrl as vm">
{{vm.name}}
</div>
</body>
</html>
Second way using controllerAs as one of the attribute of directive:
<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script>
angular.module('MyApp', [])
.directive('customDir', function() {
return {
restrict: 'EA',
template: '<div>{{vm.name}}</div>',
controller: function(){
var vm = this;
vm.name = 'Custom Directive';
},
controllerAs: 'vm'
}
});
</script>
<body>
<div ng-app="MyApp">
<div custom-dir></div>
</div>
</body>
</html>
Way to calling a function with "controller as" syntax which is defined in controller but called in html:
<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script>
angular.module('MyApp', [])
.controller('MyCntrl', function($scope) {
var vm = this;
vm.name = 'Custom Directive';
vm.someFunction = function() {
vm.name = 'Button is Clicked!!!';
};
});
</script>
<body>
<div ng-app="MyApp" ng-controller="MyCntrl as vm">
{{vm.name}}
<input type='button' ng-click="vm.someFunction()" value="Click" />
</div>
</body>
</html>
Other way, use function as constructor and add functionality to prototype
function Ctrl($window) {
this.$window = $window;
}
Ctrl.inject = ['$window']
Ctrl.prototype.click = function() {
this.$window.alert('clicked')
}
angular.module('app', [])
.controller('ctrl', Ctrl)
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='app' ng-controller='ctrl as c'>
<button ng-click='c.click()'>Click me!</button>
</div>

Share data between directive scope and controller $scope?

Here I created some sample for date picker, which is working fine but I need to set min and max date dynamically.. so i am passing the start and end date from
Html like this my-datepicker min="2013-07-23" max="2015-07-23" in directive scope i get the value and I need to set this value in controller $scope.datepickerOptions = { startDate :min, endDate:max} some thing like this..
var app = angular.module('myapp', ['ng-bootstrap-datepicker'])
app.directive('myDatepicker', function() {
return {
restrict: 'E',
template: '<input type="text" ng-datepicker ng-options="datepickerOptions" ng-model="ngModel">',
scope: {
date: '=',
ngModel: '=',
min: '=',
max: '=',
},
controller: function($scope) {
$scope.datepickerOptions = {
format: 'yyyy-mm-dd',
autoclose: true,
weekStart: 0,
startDate :'2013-07-23',
endDate:'2015-07-23'
};
}
};
})
app.controller('AppCtrl', ['$scope', function ($scope) {
$scope.date = '2013-08-12'
}]);
var appboot = angular.bootstrap(document, ['myapp']);
<link href="https://rawgit.com/cletourneau/angular-bootstrap-datepicker/master/dist/angular-bootstrap-datepicker.css" rel="stylesheet"/>
<link href="http://netdna.bootstrapcdn.com/bootstrap/2.0.4/css/bootstrap.min.css" rel="stylesheet"/>
<script src="http://code.jquery.com/jquery-2.0.2.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/2.0.4/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
<script src="https://rawgithub.com/cletourneau/angular-bootstrap-datepicker/master/dist/angular-bootstrap-datepicker.js" charset="utf-8"></script>
<body>
<div>
<div ng-app="myapp" ng-controller="AppCtrl">
<my-datepicker ng-model ="date" min="2013-07-23" max="2015-07-23"></my-datepicker>
<input id="datepickerMirror" type="text" data-ng-model="date">
</div>
</div>
</body>
$scope in the directive controller IS the isolated scope from the directive. You can just grab the values from $scope.min and $scope.max.
Update The reason your code can't do this is because you're using the '=' binding which causes your directive to look for a variable named 2013-07-23 on your scope. You either need to put your value in a variable, or change the binding to '#' and use interpolation (the curly braces {{value}}), or surround your date value with single quotes inside the double quotes as in min="'2013-07-23'" max="'2015-07-23'".
https://plnkr.co/edit/Gp5SBtIAuLq5BzzIdKfp?p=preview
var app = angular.module('myapp', ['ng-bootstrap-datepicker'])
app.directive('myDatepicker', function() {
return {
restrict: 'E',
template: '<input type="text" ng-datepicker ng-options="datepickerOptions" ng-model="ngModel">',
scope: {
dateval: '=',
ngModel: '=',
min: '=',
max: '=',
},
controller: function($scope) {
$scope.datepickerOptions = {
format: 'yyyy-mm-dd',
autoclose: true,
weekStart: 0,
startDate : $scope.min,
endDate: $scope.max
};
}
};
})
app.controller('AppCtrl', ['$scope', function ($scope) {
$scope.dateval = '2013-08-12';
$scope.min = '2013-07-23';
$scope.max = '2015-07-23';
}]);
var appboot = angular.bootstrap(document, ['myapp']);
html
<!DOCTYPE html>
<html>
<head>
<link href="//rawgit.com/cletourneau/angular-bootstrap-datepicker/master/dist/angular-bootstrap-datepicker.css" rel="stylesheet"/>
<link href="//netdna.bootstrapcdn.com/bootstrap/2.0.4/css/bootstrap.min.css" rel="stylesheet"/>
<script src="//code.jquery.com/jquery-2.0.2.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/2.0.4/js/bootstrap.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
<script src="//rawgithub.com/cletourneau/angular-bootstrap-datepicker/master/dist/angular-bootstrap-datepicker.js" charset="utf-8"></script>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body>
<div>
<div ng-app="myapp" ng-controller="AppCtrl">
<my-datepicker ng-model="dateval" min="min" max="max"></my-datepicker>
<input id="datepickerMirror" type="text" data-ng-model="dateval">
</div>
</div>
</body>
</html>
As mentioned in the previous answer's Updated comments, the reason it's not working on UPDATE is that you're "binding" (scope params with "=") to a string literal. You're likely also getting a console error when you attempt to set that variable, something along the lines of object "non-assign".
That being said, is there a reason your directive NEEDS an isolated scope? If you just set the directive up using "scope: true", then your directive will prototypically inherit from the parent scope. This reduces portability, but it doesn't look like you're really shooting for that at this point.
To setup useful prototypical inheritance you'll need to also use the "as" syntax of ng-controller in your HTML view file. For the sake of example, let's say:
ng-controller="AppCtrl as appCtl"
Then move the initialization of datepickerOptions from your directive into your main AppCtrl controller. Personally I prefer the "dot" syntax as opposed to littering the scope with variables that are hard to track, so assign it to your controller instead of scope:
this.datepickerOptions = { /* min, max, etc */ }
Now in your directive (using scope:true), you can access that controller via the directive $scope. So in your directive's controller function:
$scope.datepickerOptions = $scope.appCtl.datepickerOptions
Note that I chose the "dot" syntax here because otherwise the prototypical inheritance would create a new scope element for datepickerOptions in your directive instead of traversing up and checking the scope chain. By using the dot syntax, the previous scope variable (appCtl) is accessed, and then the sub-object lookup (datepickerOptions) causes the app to traverse the scope chain up and get the object instead of shadowing it.
The last piece to address is ngModel. If you're following along up to now, all you have to do is set the ng-model (in your directive template) to read "appCtl.modelName" where modelName is the variable you want to use. Now your controller will have that variable assigned directly to it. If you want to do something when that value changes, add this to your AppCtrl controller:
// create a variable so that it can be used in callbacks where "this" changes
var _this = this;
// Create this by hand since its ng-model binding is added dynamically by the directive template
_this.modelName = null;
$scope.$watch(function() { return _this.modelName; }, function(val, oldVal)
{
// do something here, remembering that _this contains a reference to the controller itself
});
Also note that in doing this you can get rid of that other input (datepickermirror) since all your data is already in your controller, and simply accessed by the directive.
Hope that helps!

Categories

Resources