Binding model in custom directive using this keyword - javascript

Students.html
<div class="row">
<student info="ui.Ram"></student>
</div>
Student.directive Template
<h1>{{ui.name}}</h1>
Route Config
app.config(urlRouter);
function urlRouter($routeProvider, $locationProvider) {
$routeProvider
.when('/students', {
templateUrl: 'app/views/students.html',
controller: 'prodCtrl',
controllerAs: 'ui'
})
}
Custom Directive
app.directive('student', "student");
function student() {
var directive = {};
directive.restrict = 'E';
directive.templateUrl = "Student.directive.html";
directive.scope = {
ui : "=name"
}
return directive;
});
Controller
app.controller('StudentController', StudentController);
function StudentController($scope) {
$scope.Ram= {};
$scope.Ram.name = "Mahesh";
};
When I do this way, name ("Mahesh") is reflected in UI.
I am thinking to do the same without injecting $scope in the controller.
Something like this.
function StudentController() {
var vm = this;
vm.Ram= {};
vm.Ram.name = "Mahesh";
return vm;
};
But the value is not reflecting.

You need to use controller as syntax in view to do that:
<div ng-app = "app" ng-controller = "StudentController as ctrl">
<student name = "ctrl.Ram"></student>
</div>

Related

Inject service into angular 1.5 component

I'm trying to initialize a test.service.js from an angular1.5 component and I don't really know how to that. I have used this structure for angular components:
var testComponent = {
templateUrl: "app/components/test.component.html",
controllerAs: "mvm",
bindings:{
bindingInput: "=",
},
controller: function(){
var mvm = this;
}
};
angular.module('myApp').component('testComponent', testComponent);
Just inject it using the controller as following :
...
},
controller: ['testService', function(testService){
var mvm = this;
}],
...
You can inject the service right into the controller like this:
....
controller: function(testService) {
var mvm = this;
}
};
To prevent testService getting obfuscated by a minification plugin, let the injector service know about the dependencies as well.
var Controller = function(testService) {
// Your controller code here
};
Controller.$inject = ['testService'];
var testComponent = {
...
controller: Controller, // Assign controller in component
...
};

how to inject into a directive controller in ES6

I have a directive that is written in es6. I need some services to be injected into this directive controller.
In es5, I would do something like:
function MyDirective() {
function controller(commonService) {
commonService.doSomething(this.type);
};
return {
scope: {
type: '='
},
restrict: 'E',
controller: ['commonService', controller],
controllerAs: 'vm',
templateUrl: 'myTemplate.html',
bindToController: true
};
}
angular.module('myApp').directive('myDirective', ['commonService', MyDirective]);
That way, in ES5 everything used to works just fine.
while in es6, I do:
class MyDirective {
constructor(commonService) {
this.scope = {
type: '='
};
this.restrict = 'E';
this.controllerAs = 'vm';
this.templateUrl = 'myTemplate.html';
this.bindToController: true;
}
controller() {
commonService.doSomething(this.type);
}
}
angular.module('myApp').directive('myDirective', [('commonService') => MyDirective(commonService)]);
The problem now is: I can no longer inject commonService into my controller.
I have tried to use
this.commonService = commonService;
in the constructor function, but unfortunatlly, I don't have access to "this" inside the controller for some odd reason. (Isn't that the whole point of having a class in the first place?)
How do I inject my commonService into the controller function, or alternatively, how do I gain access to "this" from the controller function?
Thanks!
One option is to define the controller as a class.
The DEMO
class MyDirective {
constructor() {
this.scope = {
type: '#'
};
this.restrict = 'E';
this.controller = 'myDirectiveCtrl',
this.controllerAs = 'vm';
this.template = `
<fieldset>
myDir type={{vm.type}}
<br> Service {{vm.serviceType}}
</fieldset>`;
this.bindToController = true;
}
}
class MyDirectiveCtrl {
constructor(commonService) {
this.commonService = commonService;
}
$onInit() {
this.serviceType = this.commonService.doSomething(this.type);
}
}
MyDirectiveCtrl.$inject = ['commonService'];
angular.module('myApp',[])
.directive('myDirective', MyDirective)
.controller("myDirectiveCtrl", MyDirectiveCtrl)
.value("commonService", {
doSomething: (type) => ("--"+type+"--")
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="myApp">
<h1>ES6 Directive Demo</h1>
<my-directive type="IDK"></my-directive>
</body>

AngularJS ng-controller directive does not accept variable (scope function) from javascript, does not give any error either

I am relatively new to angularJS, I am trying to set up a page where inturn multiple pages are called depending upon the selection made previously.
All the pages have their own controller, so I am trying to set the controller and view src through the javascript and using them in HTML tags.
Following is what I am doing:
HTML page:
<div ng-if="sidebarName=='sidebar-device-wire'">
<div ng-controller="getSidebarCtlr">
<div ng-include src="sidebarSrc"></div>
</div>
</div>
javascript:
$scope.sidebarSrc="views/sidebars/sidebar-device.html";
$scope.sidebarCtlr="SidebarDeviceCtrl";
$scope.getSidebarCtlr = function(){return $scope.sidebarCtlr;}
For some reason though, this does not work. i can get the HTML page but the controller is not being called. Can anyone please tell me what I am doing wrong?
I would also recommend to use ngRoute or ui.router because there are many features that aren't easy to implement from scratch (like named views, nested views / nested states or resolves) and these modules are well tested.
Not sure why your controller isn't running but I guess that the expression of the controller is evaluated before your controller that is setting the name is running. So it will be always undefined at compile time.
But if you really like to implement a very basic router you could do it like in the following demo (or in this fiddle).
Update 21.12.2015
Here are some router examples that I wrote for other SO questions:
simple ui.router example - jsfiddle
more complex nested state example ui.router - jsfiddle
dynamic link list with ngRoute - jsfiddle
Please also have a look at ui.router github pages to learn more about it.
angular.module('simpleRouter', [])
.directive('simpleView', simpleViewDirective)
.provider('simpleRoutes', SimpleRoutesProvider)
.controller('MainController', MainController)
.controller('HomeController', HomeController)
.config(function(simpleRoutesProvider) {
simpleRoutesProvider.state([{
url: '/',
templateUrl: 'home.html',
controller: 'HomeController'
}, {
url: '/view1',
templateUrl: 'view1.html'
}, {
url: '/view2',
templateUrl: 'view2.html',
controller: function($scope) {
$scope.test = 'hello from controller'
}
}]);
simpleRoutesProvider.otherwise('/');
})
function HomeController($scope) {
$scope.hello = 'hello from home controller!!';
console.log('home controller started')
}
function MainController($scope) {
$scope.hello = 'Main controller test';
}
function simpleViewDirective() {
return {
restrict: 'EA',
scope: {},
template: '<div ng-include="templateUrl"></div>',
controller: function($scope, $location, $controller, simpleRoutes) {
var childControllerInst;
$scope.templateUrl = simpleRoutes.currentRoute.templateUrl || simpleRoutes.otherwise.templateUrl;
$scope.$watch(function() {
return $location.path();
}, function(newUrl) {
//console.log(newUrl)
$scope.templateUrl = simpleRoutes.changeRoute(newUrl);
childControllerInst = $controller(simpleRoutes.currentRoute.controller || function() {}, {$scope: $scope});
});
$scope.$on('$destroy', function() {
childControllerInst = undefined;
})
},
link: function(scope, element, attrs) {
}
}
}
function SimpleRoutesProvider() {
var router = {
currentRoute: {
templateUrl: ''
},
states: [],
otherwise: {},
changeRoute: function(url) {
var found = false;
angular.forEach(router.states, function(state) {
//console.log('state', state);
if (state.url == url) {
router.currentRoute = state;
found = true;
}
});
if (!found) router.currentRoute = router.otherwise;
//console.log(router.currentRoute);
return router.currentRoute.templateUrl;
}
};
this.state = function(stateObj) {
router.states = stateObj;
};
this.otherwise = function(route) {
angular.forEach(router.states, function(state) {
if (route === state.url ) {
router.otherwise = state;
}
});
//console.log(router.otherwise);
};
this.$get = function simpleRoutesFactory() {
return router;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="simpleRouter" ng-controller="MainController">
<script type="text/ng-template" id="home.html">home route {{hello}}</script>
<script type="text/ng-template" id="view1.html">view1</script>
<script type="text/ng-template" id="view2.html">view2 {{test}}</script>
<div simple-view="">
</div>
home
view1
view2
<br/>
{{hello}}
</div>
What's that code means? $scope.getSidebarCtlr = function(){return $scope.sidebarCtlr;}
the ng-directive requires a Controller name, its argument type is string and you cannot pass a simple function, you need to register a valid controller associating it to a module via the controller recipe.
https://docs.angularjs.org/guide/controller
angular.module('test', []).controller('TestCtrl', function($scope) {
$scope.greetings = "Hello World";
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<section ng-app="test">
<article ng-controller="TestCtrl">{{ greetings }}</article>
</section>

Update directive scope when attribute changes using controllerAs syntax

What I need is to inject the data inside a directive dependent on the value passed to this directive via HTML element attribute value, which changes dynamically.
Here's my code:
angular.module('test', [])
.controller('ctrl', function (dataService) {
var vm1 = this;
vm1.data = dataService;
vm1.change = function () {
vm1.data.testValue = !vm1.data.testValue;
}
})
.directive('myDrct', function () {
return{
restrict: 'E',
controller: 'drctCtrl',
controllerAs: 'vm',
scope:{
passedValue: '#pass'
},
template: 'Actual value in directive: {{vm.passedValue}}'
}
})
.controller('drctCtrl', function ($scope) {
var vm = this;
vm.passedValue = $scope.passedValue;
$scope.$watch('watcher', function () {
vm.passedValue = $scope.passedValue;
})
})
.factory('dataService', function () {
return{
testValue: true
}
});
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.min.js"></script>
<div ng-app="test" ng-controller="ctrl as vm">
Value passed as a parameter to directive: {{vm.data.testValue}}
<button ng-click="vm.change()">change</button>
<div>
<my-drct pass="{{vm.data.testValue}}"></my-drct>
</div>
</div>
And here is a demo plunker:
http://plnkr.co/edit/aAqKaD4G7QdwBYCLWAvM?p=preview
As suggested in many similar topics on StackOverflow, I've tried $scope.$watch, but I must be doing something wrong. The value gets inserted to the directive once and it doesn't get updated when the attribute value changes.
What shoud I change in the watcher function to get it to work? Or maybe this approach is not good at all in my case and I should try something else?
EDIT:
I must use "controllerAs vm" syntax, since this code is just a part of a bigger app already dependent on it.
The only thing you needs to change in your code in controller: vm.scope = $scope; instead of vm.passedValue = $scope.passedValue; and in a template change {{vm.passedValue}} to {{vm.scope.passedValue}}
Plunker: http://plnkr.co/edit/q8JBFu4FD5ECPFHYlPg6?p=preview
angular.module('test', [])
.controller('ctrl', function (dataService) {
var vm1 = this;
vm1.data = dataService;
vm1.change = function () {
vm1.data.testValue = !vm1.data.testValue;
}
})
.directive('myDrct', function () {
return{
restrict: 'E',
controller: 'drctCtrl',
controllerAs: 'vm',
scope:{
passedValue: '#pass'
},
template: 'Actual value in directive: {{vm.scope.passedValue}}'
}
})
.controller('drctCtrl', function ($scope) {
var vm = this;
vm.scope = $scope;
})
.factory('dataService', function () {
return{
testValue: true
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test" ng-controller="ctrl as vm">
Value passed as a parameter to directive: {{vm.data.testValue}}
<button ng-click="vm.change()">change</button>
<div>
<my-drct pass="{{vm.data.testValue}}"></my-drct>
</div>
</div>

Bind a service variable to a directive?

I have a controller which contains a function that gets some data from the server. I store that data in a service variable. This service is then injected into a directive. I want the directive to be auto updated, whenever this function is called and the data is renewed.
My controller:
angular
.module('myApp')
.controller('myCtrl', ['$scope', 'SomeService', function($scope, SomeService) {
$scope.update = function() {
SomeService.myValue = 100;
}
}]);
The directive:
angular.module('myApp')
.directive('myDirective', ['SomeService', function(SomeService) {
return {
templateUrl : 'views/myDirective.html',
restrict : 'E',
scope : false,
controller : function($scope) {
this.myValue = SomeService.myValue;
}
};
}]);
The template:
<div>
{{ myValue }}
</div>
The update function is called when a button is clicked and it updates myValue to a new value. I want it to be automatically reflected in the directive.
Plunk: http://plnkr.co/edit/OUPzT4MFS32OenRIO9q4?p=preview
Please see working demo below
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope, SomeService) {
$scope.name = SomeService.data;
$scope.update = function() {
$scope.name.myValue += 1;
}
});
app.factory('SomeService', function() {
var data = {
myValue: 0
};
return {
data: data
}
});
app.directive('myDirective', ['SomeService',
function(SomeService) {
return {
templateUrl: 'myDirective.html',
restrict: 'EA',
scope: false,
link: function(scope, elem, attr) {
scope.data = SomeService.data
}
};
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="MainCtrl">
<p>My Value: {{name.myValue}}</p>
<button ng-click="update()">Click</button>
<hr/>
<div my-directive></div>
<script type="text/ng-template" id="myDirective.html">
<h3>My Directive</h3>
<p>Value: {{data.myValue}}</p>
</script>
</div>
</div>
You can try by adding the reference of the service to the directive itself..
The directive:
angular.module('myApp')
.directive('myDirective', ['SomeService', function(SomeService) {
return {
templateUrl : 'views/myDirective.html',
restrict : 'E',
scope : false,
controller : function($scope) {
this.SomeService = SomeService;
}
};
}]);
The template:
<div>
{{ SomeService.myValue }}
</div>
Edit : I went through your plunker, and have finally got it working.
You can check the updated code here
#RutwickGangurde and others who were having issues, if you're trying to set a scope variable that is not an object it won't work. I'm guessing that's what you're currently doing in your service:
...
this.myVar = true;
...
and then trying to set it in the directive/controller:
...
scope.myVar = myService.myVar;
...
That will NOT work for getting the updated variable in the service when it changes.
Try this instead in your service:
...
this.myObj = {};
this.myObj.myVar = true;
...
and in your directive/controller:
...
scope.myValue = myService.myObj;
...
and in your html:
...
{{ myValue.myVar }}
...
I would have made this as a comment, but I don't have sufficient privileges yet so decided to post as a response with a very brief example.

Categories

Resources