Passing data between components in AngularJS - angularjs

I'm having trouble linking two brother components in angularJS without using a service. I saw examples but I can not make them work. This is what I have. What am I failing? Thanks!
cluster.js
<div class="row">
<filter-component></filter-component>
<result-component filters="$ctrl.filters"></result-component>
</div>
filter.component.js
'use strict';
angular
.module('filter' , ['ui.bootstrap'])
.component('filterComponent', {
bindings: {},
templateUrl : 'app/filter/filter.html',
controller : filterCtrl
})
function filterCtrl($scope){
this.filters = 'FILTRO' // <-- I give it a value
}
results.component.js
(function(){
'use strict';
angular
.module('result')
.component('resultComponent', {
bindings: {
filters :'<' // <-- inject
},
templateUrl : 'app/result/result.html',
controller : resultCtrl
})
function resultCtrl($scope) {}
result.html
<h1>{{$ctrl.filters}}</h1> //<-- nothing is shown :(

Use an attribute with expression binding in the HTML:
<div class="row">
<filter-component on-update="$ctrl.filters=$filters">
</filter-component>
<result-component filters="$ctrl.filters">
</result-component>
</div>
Use expression binding with & in <filter-component>:
app.component('filterComponent', {
bindings: {onUpdate: "&"},
templateUrl : 'app/filter/filter.html',
controller : filterCtrl
})
function filterCtrl() {
this.filters = 'FILTRO' // <-- I give it a value
this.onUpdate({$filters: this.filters});
}
For more information, see
AngularJS Developer Guide - Component-based application architecture
AngularJS Comprehensive Directive API - isolate scope bindings

Related

How to inject service dependencies from templates into controllers?

I have the following template.html:
<html>
...
<my-tab></my-tab>
...
</html>
Tag <my-tab> is represented by tabTemplate.html and managed by a MyTab controller with the following constructor:
constructor(
private firstService: FirstServiceClass,
){
this.doSomething(); // this fuction uses firstService
}
FirstServiceClass - a custom class.
I have another tags like <my-tab2>, <my-tab3> etc. They are managed by MyTab2, MyTab3 controllers.
The code of these controllers is almost the same, the difference between them is a parameter in a constructor.
I need to remove copypaste.
Is it possible to specify this parameter somehow?
Use component bindings:
app.component("myTab", {
bindings: {
tab: "<"
},
controller: "myTabController",
templateURL: "myTab.html"
}
Usage:
<my-tab tab="0"></my-tab>
<my-tab tab="1"></my-tab>
class myTabController {
constructor (firstService) {
//...
}
$onInit() {
console.log(this.tab);
//...
}
}
For more information, see
AngularJS Developer Guide - Component-based Architecture
for tab="0" it's needed to use myTabController constructor(firstService). for tab="1" it's needed to use myTabController constructor(secondService). Is it possible?
Use the $injector service to inject different services:
app.component("myTab", {
bindings: {
tab: "<",
service: "#"
},
controller: "myTabController",
templateURL: "myTab.html"
}
class myTabController {
constructor ($injector) {
this.$injector = $injector;
}
$onInit() {
this.tabService = this.$injector.get(this.service);
//...
}
}
Usage:
<my-tab tab="0" service="firstService"></my-tab>
<my-tab tab="1" service="secondService"></my-tab>
For more information, see
AngularJS $injector Service API Reference - get
you can create a directive for my-tab that would be better for binding new temple for this directive and use a model controller for logic.
////This html will be inside parents controller
<div class="tabClass hide">
<my-tab></my-tab>
</div>
////////////////////
'use strict';
angular.module('demoApp').directive('myTab', function () {
return {
templateUrl: "~/MyTab.html",//Create a template for directive view named like MyTab
restrict: "E",
controller: function ($scope, $routeParams, $http, $filter, $modal ) {
//essential code
}
};
});
//and finally add directive referance to index file or where you referances other js file in your project

what is angular UI components ? can any one please tell me

Is there any difference between custom directives and Ui components. please anyone tell me the difference and usage.
A component is a 'reusable UI building block for an application' which creates it's own view (new hierarchy of DOM elements) with behaviour.
#Component({selector: 'greet', template: 'Hello {{name}}!', directives: [CustomDirective]})
class Greet {
name: string = 'World';
}
which could be used as html:
<greet></greet>
A directive adds behaviour to an existing element (DOM) via event listeners.
angular.module('simpleDirective', [])
.controller('Controller', ['$scope', function($scope) { }])
.directive('myDirective', function() {
return {
template: ''
};
});
which can be used as:
<div ng-controller="Controller">
<div my-directive></div>
</div>

What can be the reason to use "controllerAs" property?

I am working on an AngularJS tutorial, and I see the following code:
.state('index',{
url:"/",
templateUrl:"views/index.html",
controller:"IndexCtrl",
controllerAs:"index"
})
What is the reason someone would want to use the controllerAs property?
Few things:
1. Reduce scope usage
Instead of loading every data in the scope of a controller, you could simply use this to load up everything that you require.
eg:
Route
state('index',{
url:"/",
templateUrl:"views/index.html",
controller:"ListCtrl",
controllerAs:"list"
})
In Controller
angular.module('feed').controller('ListCtrl', function($scope, reddit){
var vm = this;
vm.names = ["Michael", "Roy"];
});
In Template:
<ul>
<li ng-repeat="name in list.names">
<div>{{name}}</div>
</li>
</ul>
2. Correct scope usage
When multiple controllers come into play, scope becomes a tricky thing. Using controllerAs method will go a long way is resolving this. An example is shown below:
Wrong:
<span>Outside Controller: Your name is: {{username}}</span>
<div ng-controller="SignupController">
<span>Inside Controller: Your name is: {{username}}</span>
<fieldset legend="User details">
<input ng-model="username">
</fieldset>
</div>
Correct:
<span>Outside Controller: Your name is: {{user.name}}</span>
<div ng-controller="SignupController">
<span>Inside Controller: Your name is: {{user.name}}</span>
<fieldset legend="User details">
<input ng-model="user.name">
</fieldset>
</div>
Found an image which makes everthing more clear:
Courtesy : AngularJs "controller as" syntax - clarification?
Yes. A little more info:
Before the controllerAs syntax, methods and properties needed to be exposed to views by binding them to the $scope. With controllerAs, your controller instance is bound to the $scope as the property you select.
This way you can use Plain Old JavaScript Classes for your controllers.
Editorial: This is a much cleaner approach to development. One of the things that makes Angular so easy to write tests for is that your Controllers and components do not need to inherit from framework base-classes. See Backbone and Ember.
So with the old style your controllers would look like (in ES6 for simplicity):
YourController.$inject = ['$scope'];
class YourController {
constructor($scope) {
$scope.myMethod = () => { . . . };
$scope.myProperty = true;
}
}
With the controllerAs
class YourController {
constructor() {
this.myProperty = true;
}
myMethod() { . . . };
}
Just a plain old class rather than decorating or monkeypatching the $scope.
maybe you didn't googled enough!
http://toddmotto.com/digging-into-angulars-controller-as-syntax/
As the name "controllerAs" tell us, is an alias for controller them you can access your controller with that alias.
You can set your controller in many ways like :
$stateProvider.state('contacts', {
template: '<h1>{{title}}</h1>',
controller: function($scope){
$scope.title = 'My Contacts';
}
})
Or if you already have a controller defined on the module, like this:
$stateProvider.state('contacts', {
template: ...,
controller: 'ContactsCtrl'
})
Alternatively using the controllerAs syntax the above become:
$stateProvider.state('contacts', {
template: '<h1>{{contact.title}}</h1>',
controller: function(){
this.title = 'My Contacts';
},
controllerAs: 'contact'
})
and
$stateProvider.state('contacts', {
template: ...,
controller: 'ContactsCtrl as contact'
})
Or for more advanced needs you can use the controllerProvider to dynamically return a controller function or string for you:
$stateProvider.state('contacts', {
template: ...,
controllerProvider: function($stateParams) {
var ctrlName = $stateParams.type + "Controller";
return ctrlName;
}
})
Source : https://github.com/angular-ui/ui-router/wiki#controllers
Simply, Controller as syntax helps when we are working with nested controllers. The named scopes are clearly defined so there won’t be conflicts between controllers since you must state which controller you’re referencing before the dot.
<div ng-controller="Shell as shellVm">
<h1>{{shellVm.title}}</h1>
<article ng-controller="Customers as customersVm">
<h2>{{customersVm.title}} in {{shellVm.title}}</h2>
<ul ng-repeat="c in customersVm.customers">
<li>{{c.name}}</li>
</ul>
</article>
</div>
Refer AngularJs "controller as" syntax - clarification? as well.

Directive with transclude, data binding not working in templateUrl

I have a directive with transclude:true. However, the data binding works when i use a template:"" but not when i use templateUrl:""
Below you can find my directive. The rsCarousel.html template contains the same code as the template"" property.
When using the template property i get the vm.carouselId on screen but not when using the templateUrl property.
Why is this?
Thx,
(function () {
'use strict';
angular.module('skynetDashboard').directive('rsCarouseli', carouseli);
function carouseli(){
var directive = {
restrict:"EA",
scope:{
carouselData:"=",
carouselId:"#",
carouselOptions:"#"
},
transclude:true,
templateUrl:"js/directive/rsCarousel.html",
//template:"<strong>ID: {{vm.carouselId}}</strong><ul ng-transclude></ul>",
bindToController:true,
controllerAs:"vm",
link:link,
controller:controller
}
return directive
function link(scope){
console.log(scope.vm)
}
controller.$inject = [""]
function controller(){
}
}
})();
That is strange, scope binding should work in both cases.
Be sure that your template file is not cached by the browser (and using an old version of it).

angular.js controller as syntax template binding using $template cache service

i have already used angular js before but now i am using controller as syntax in angular js and i am not able to bind template.
My controller code:
(function () {
angular.module("vkApp")
.controller("Feeds", Feeds);
function Feeds(FeedSetting, FeedLoader, $templateCache, $compile) {
var vm = this;
FeedSetting.initializeSetting(vm);
//functions declaration
vm.addFeed = addFeed;
// function implementations
function addFeed(text) {
return FeedLoader.loadFeed("http://rss.cnn.com/rss/edition_world.rss")
.then(function (feedData) {
console.log(feedData.data.responseData.feed);
vm.feedList = feedData.data.responseData.feed;
var feedTemplate = $templateCache.get("feedTemplate");
feedTemplate.then(function (markup) {
$compile(markup.data)(vm).appendTo(angular.element("#FeedArea"));
});
return vm.feedList;
});
}
};
})();
My template is:
<h7>{{feed.feedList.title}}</h7>
feed.html page:
<div id="rightSide" ng-controller="Feeds as feed">
<div class="news-feed-wrapper" id="FeedArea">
</div>
</div>
when the binding is performed it gives me error in console
You need to make couple of changes
1)Replace this line
$compile(markup.data)(vm).appendTo(angular.element("#FeedArea"));
with
$compile(markup.data)($scope).appendTo(angular.element("#FeedArea"));
because behind the scene your custom variable vm bind with Angular $scope. So $compile would work the same like it was using classic controller with $scope syntax
2) And in your binding replace
<h7>{{feed.feedList.title}}</h7>
with
<h7>{{vm.feedList.title}}</h7>
3) And inside Feed.html
ng-controller="Feeds as feed"
should be
ng-controller="Feeds as vm"
After the above changes it should work.

Resources