login.js
var app= angular.module('login',[]);
app.controller('LoginCtrl', function($scope)
{
$scope.sayhello="Hello"+ $scope.username;
}).directive('loginDir', function(){
return {
scope:{},
templateUrl: 'logintpl.html',
controller: 'LoginCtrl'
};
});
var adapter = new ng.upgrade.UpgradeAdapter();
AppComponent = ng.core
.Component({
selector: 'login',
directives: [adapter.upgradeNg1Component('loginDir')],
template: '<login-dir></login-dir>'
})
.Class({
constructor: function() {}
});
app.directive('login', adapter.downgradeNg2Component(AppComponent));
document.addEventListener('DOMContentLoaded', function() {
adapter.bootstrap(document.body, ['login']);
console.log(adapter);
});
logintpl.html
<input type="name" ng-model="username">
how can i use $scope.sayhello variable inside the component.
eg: component template should be,template:'<login-dir></login-dir>{{sayhello}}
AppComponent = ng.core
.Component({
selector: 'login',
directives: [adapter.upgradeNg1Component('loginDir')],
template: '<login-dir></login-dir> {{sayhello}}'
})
.Class({
constructor: function() {
this.sayhello = "Hello World !!!";
}
});
Explanation
In Angular 2, there is no model called $scope. They replaced it with simple variables with in the Class.
We can consider the whole Class as a controller in Angular 1.x. We can create variable with this.variable_name with in a Class. constructor is the function which will be invoked first in the component. So, we can initialize all our variable here.
So, $scope.variable_name in Angular 1.x is same (or likely to) as this.variable_name in Angular 2.
In fact the sayhello attribute can be only used within your loginDir directive since it's defined in its associated scope.
You could have a use case like that:
app.controller('LoginCtrl', function($scope) {
$scope.sayhello = function() {
console.log("Hello"+ $scope.username);
}
}).directive('loginDir', function() {
return {
scope:{},
templateUrl: 'logintpl.html',
controller: 'LoginCtrl'
};
});
In the template of your Angular1 directive, you will be able to use this function:
<input type="name" ng-model="username">
<span ng-click="sayhello()">Test</span>
I don't know what you exactly want to do. Here is the corresponding plunkr: https://plnkr.co/edit/ribHwk8uSXHRv0JkLlo0?p=preview.
Edit
You can have access to attributes of the parent component from the directive since the Angular1 directive scope is internal to your directive. With Angular1, you can't either. The only thing you could do is to define a parameter to your Angular1 directive that corresponds to an attribute of your parent component and update it by reference.
Here is a sample
app.controller('LoginCtrl', function($scope) {
$scope.updateSayhelloInParent = function() {
console.log("Hello"+ $scope.username);
$scope.sayhello.message = $scope.username;
}
}).directive('loginDir', function(){
return {
scope:{
sayhello: '='
},
templateUrl: 'logintpl.html',
controller: 'LoginCtrl'
};
});
And the way to use the directive in the component:
AppComponent = ng.core
.Component({
selector: 'login',
directives: [adapter.upgradeNg1Component('loginDir')],
template: `
<login-dir [sayhello]="sayHello"></login-dir>
<br/><br/>
SayHello in component:
{{sayHello | json}}
`
})
.Class({
constructor: function() {
this.sayHello = {
message: 'default message'
}
}
});
Corresponding plunkr is here: https://plnkr.co/edit/ribHwk8uSXHRv0JkLlo0?p=preview.
Hope it helps you,
Thierry
Related
This question already has an answer here:
How to update child components from the updated list of parents
(1 answer)
Closed 4 years ago.
I have parent component:
(function () {
angular.module('app.module')
.component('parentComponent', {
templateUrl: 'parent.html',
controllerAs: 'vm',
controller: function ($scope) {
this.$onInit = () => {
$scope.parentData = 'test'
}
})
})()
child component
(function () {
angular.module('app.module').component('childComponent', {
templateUrl: 'child.html',
controllerAs: 'vm',
controller: function () {
this.$onInit = () => {
}
}
})
})()
parent.html
<child-component></child-component>
child.html
<p>{{parentData}}</p>
So I want to have access to parentData in my child component for display string 'test' in my child component. How can I do it? I read something about bindings but I don't know how to use it in this example.
Thanks for any suggestions.
Use one-way < binding:
<child-component in-data="$ctrl.parentData"></child-component>
The child component:
app.component("childComponent", {
bindings: {
inData: '<',
},
template: `
<div>{{$ctrl.inData}}</div>
`,
})
The DEMO
angular.module("app",[])
.component("parentComponent", {
template: `
<fieldset>
Inside parent component<br>
parentData={{$ctrl.parentData}}
<child-component in-data="$ctrl.parentData"></child-component>
</fieldset>
`,
controller: function () {
this.$onInit = () => {
this.parentData = 'test'
};
},
})
.component("childComponent",{
bindings: {
inData: '<',
},
template: `
<fieldset>Inside child component<br>
inData={{$ctrl.inData}}
</fieldset>
`,
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app">
<parent-component>
</parent-component>
<body>
For more information, see
AngularJS Developer Guide - Component-based application architecture
AngularJS Comprehensive API Reference - scope
You can access parent's data via the parent controller, for that you can use require in your component declaration:
Here is an example:
app.component('childComponent', {
require: {
parentCtrl: '^parentComponent'
},
controller: function() {
var self = this;
this.$onInit = function() {
self.parentCtrl.anyData;
};
}
});
Take a look at codelord.net - Advanced Angular 1.x: Component Communication with Require
If you don't need the parent controller you can bind data to your child component: refer to #georgeawg answer
I'm trying to output my scope data from my component, but having a hard time figuring out how to do it without a local template.
For different reasons I need to have the markup ind the HTML file and not being parsed in with the js load
This is the dummy code so far: (codepen: http://codepen.io/anon/pen/qNBBRN)
HTML:
<comp>
{{ $ctrl.testing }}
</comp>
Non-working JS code:
angular
.module('Test', [])
.component('comp', {
controller: myCtrl,
});
function myCtrl() {
var model = this;
model.testing = '123';
}
document.addEventListener('DOMContentLoaded', function() {
angular.bootstrap(document, ['Test']);
});
And this is what I want to avoid even though it works:
angular
.module('Test', [])
.component('comp', {
controller: myCtrl,
template: '{{ $ctrl.testing }}',
});
function myCtrl() {
var model = this;
model.testing = '123';
}
document.addEventListener('DOMContentLoaded', function() {
angular.bootstrap(document, ['Test']);
});
A solution to what you need is using bindings to relate the component's inner private scope with the parent scope.
JS
angular
.module('Test', [])
.component('comp', {
controller: myCtrl,
bindings: {
testing: '='
}
});
function myCtrl() {
var model = this;
model.testing = '123';
}
HTML
<comp testing="$ctrl.testing">
{{ $ctrl.testing }}
</comp>
Plunkr example: http://plnkr.co/edit/jLeDyBTFA9OU7oqK5HSI?p=preview
(Using Angular 1.5)
I am trying to use the following design pattern for my angular app:
angular.module("app").directive("MyDirective", MyDirective);
function MyDirective () {
return {
bindToController: {
someId: "=",
otherAttr: "#"
},
controller: ["$attrs", MyController],
controllerAs: "ctrl"
};
}
function MyController ($attrs) {
var self = this;
console.log(self);
console.log($attrs);
}
I use my directive in my HTML like this:
<my-directive someId="someParentScope.model._id" otherAttr="1">
In the console, for self I see:
Object { otherAttr: undefined, someId: undefined }
and for $attrs I see:
Object { $attr: Object, $$element: Object, otherattr: "1",
someid: "someParentScope.model._id", otherAttr: undefined, someId: undefined,
$$observers: Object }
How may I accomplish what I am trying to accomplish (i.e. passing data from parent scope into my directive controller constructor), and why is even my single binding ("#" binding) otherAttr undefined in the controller constructor? Is this design pattern is flawed/misguided? Thanks!
looks like you have the naming conventions wrong on the directive, you should define the name on directive attribute as "data-content" and use on the controller as "dataContent"
Take a look this demo i've done
// directive HTML
<my-directive some-id="name" other-attr="1"></my-directive>
//app.js
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
});
app.directive('myDirective', function() {
return {
restrict: 'E',
bindToController: {
someId: "=",
otherAttr: "#"
},
controller: ["$attrs", MyController],
controllerAs: "ctrl"
}
});
function MyController ($attrs) {
var self = this;
console.log(self);
console.log($attrs);
}
http://plnkr.co/edit/P3VKdO?p=preview
I'm trying to get a directive to work with its own controller:
http://jsfiddle.net/edwardtanguay/xfbgjun5/14/
However, when I click the button:
var template = '<button ng-click="vm.addItem()">add item</button>'+
'<ul><li ng-repeat="item in vm.items">{{item}}</li></ul>';
It tells me that:
Error: vm.add is not a function
even though I define controllerAs and bindToController:
return {
restrict: 'A',
scope: {
datasource: '=',
add: '&'
},
controller: controller,
controllerAs: 'vm',
bindToController: true,
template: template
};
and pass in a scope method from the main controller:
<div item-menu datasource="customers" add="addCustomer()"></div>
Why does it not recognize add as a function on vm?
ADDENDUM: The controller looks like this:
.controller('mainController', function ($scope) {
$scope.customers = ['First','Second','Third'];
$scope.score = 0;
$scope.addCustomer = function() {
$scope.score++;
}
})
You can find the answer to your question in this blog post
If you use Angular 1.3 you need to add to the directive the following line of code:
bindToController: true,
Check the blog post and the code snippets.
When you bind to attributes, you have to bind it to $scope, not the controller.
var controller = function($scope) {
var vm = this;
function init() {
vm.items = angular.copy($scope.datasource);
}
init();
vm.addItem = function() {
$scope.add();
vm.items.push('new one');
}
}
http://jsfiddle.net/xfbgjun5/15/
I'm using AngularUI router (0.2.13) and have a state defined as such
.state('foo', {
template:'<div some-directive></div>',
resolve: {
foo: function(SomeService) {
return SomeService.something().promise;
}
}
})
and a directive like this:
app.directive('someDirective', function(){
return {
controller: function(data) {
// I want `data` to be injected from the resolve...
// as it would if this was a "standalone" controller
}
}
})
but this doesn't work - the data parameter causes an UnknownProvider error. Defining the directive controller independently and setting it by name in the directive has the same result.
I more or less get why this is happening, but have two questions:
is there a way to do what I'm trying to do?
should I be trying to do it, or have I slipped into an antipattern here?
You can't use resolves in directives, but you can pass the result resolved in the state down to the directive which I think accomplishes what you're looking for.
You'd want to update your state definition to include a controller and set a parameter on the directive:
.state('foo', {
template:'Test<div some-directive something="foo"></div>',
url: 'foo',
resolve:{
foo:function(SomeService){
return SomeService.something();
}
},
controller: function($scope, foo){
$scope.foo = foo;
}
})
Then update the directive to use this parameter:
.directive('someDirective', function(){
return {
controller: function($scope) {
// I want `data` to be injected from the resolve...
// as it would if this was a "standalone" controller
console.log('$scope.something: '+ $scope.something);
},
scope: {
something: '='
}
};
})
Here's a sample plunker: http://plnkr.co/edit/TOPMLUXc7GhXTeYL0IFj?p=preview
They simplified the api. See this thread:
https://github.com/angular-ui/ui-router/issues/2664#issuecomment-204593098
in 0.2.19 we are adding $resolve to the $scope, allowing you to do "route to component template" style
template: <my-directive input="$resolve.simpleObj"></my-directive>,