Angular js binding "<" give undefined inside controller - angularjs

I have "invite-friends-code" component which get data through binding "<". The problem is, it is pass correctly and show in the view directly, but when i trying to munipulate with it inside "invite-friends-code" controller it gives me "undefined"
component
const inviteFriendsCodeComponent = {
bindings: {
leagueCode: '<'
},
templateUrl: '/js/common/invite-friends-code/invite-friends-code.html'+assetsVersion,
controller: 'InviteFriendsCodeController'
}
binding using inside other component view:
<invite-friends-code league-code="$ctrl.leagueData.code"></invite-friends-code>
controller:
ctrl.$onInit = () => {
console.log(ctrl.leagueCode) // gives me undefined here
}

Your bindings are not initialized yet!
You can use $onInit function.
app.component('yourComponent', {
bindings: {
leagueCode: '<'
},
controller: function() {
var ctrl = this;
this.$onInit = function() {
console.log(this.leagueCode)
});
}
}
Official doc

Related

Unable to pass data to a controller inside a component in AngularJS

I have following component
componentsModule.component('detailComponent', {
templateUrl: 'detailTemplate.html',
scope: {},
bindings: {
textParam: '='
},
controller: ['$mdDialog', function($mdDialog) {
this.textParam // this is undefined always
}]
});
I am loading template in a dialog from other controller like this
$scope.textParam = tParam;
const parentEl = angular.element(document.body);
$mdDialog.show({
template: '<detail-component text-param="$scope.textParam"></detail-component>',
ariaLabel: 'detailComponentDialog',
parent: parentEl
}).then((savedDatails) => {});
If I use binding as # then I get $scope.textParam as a string inside my controller in this.textParam but if I set binding as < or = then I get undefined

Can't add an attribute to an element using $postLink - AngularJS

I have a simple component and what I'm trying to do is to add to my input element an attribute multiple dynamically but somewhy it doesn't work. Why? And is there any way to do what I want?
app.component('myComponent', {
templateUrl: 'tmpl.html',
bindings: {
str: '#'
},
controller: function () {
var ctrl = this;
ctrl.$postLink = function () {
$('#myInputId').attr('multiple', '');
}
}
}
This is the solution:
app.component('myComponent', {
templateUrl: 'tmpl.html',
bindings: {
str: '#'
},
controller: function ($element) {
var ctrl = this;
ctrl.$postLink = function () {
$element.find('input').attr('multiple', 'multiple');
}
}
}
The trick was in linking stuff. Code from the question doesn't work because the input not exists in DOM yet at the time $postLink hook triggered. So what we need is to inject $element service into controller and use it to manipulate DOM.

angular 1.5 component binding not updated from certain events

I have an angular 1.5 component (i.e. myCarousel: it wraps a bootstrap carousel) that triggers an event and exposes it with a function binding.
A parent container (i.e. myContainer) component binds a function to that event and modifies some inner state when triggered.
Another child-component of the parent container is bound to the container's inner state.
The problem:
When I trigger the event on myCarousel from a button click event, everything works fine and I can see the child-component's binding being updated.
However, when I trigger the event from a carousel slide event (slide.bs.carousel), the binding does not get updated.
Here's a plunker to demonstrate:
https://plnkr.co/edit/AHxaX8o0sE94Nfir7DVB
Can anyone explain why this is happening and how to solve this?
Some relevant code:
mainApp.component("myCarousel", {
templateUrl: "myCarousel.html",
bindings: {
onEventTriggered: "&"
},
controllerAs: "vm",
controller: function() {
let vm = this;
vm.$onInit = function() {
console.log("init!");
$("#theCarousel").carousel();
$("#theCarousel").on("slide.bs.carousel", (event) => {
console.log("sliding " + event.direction);
vm.onEventTriggered();
});
};
}
});
mainApp.component("myContainer", {
templateUrl: "myContainer.html",
controllerAs: "vm",
controller: function() {
let vm = this;
vm.counter = 0;
vm.triggerEvent = function() {
console.log("event!");
vm.counter++;
}
}
});
mainApp.component("childComponent", {
template: "<div>Event {{vm.attribute}}</div>",
controllerAs: "vm",
bindings: {
attribute: "<"
}
});
One way to do this is :
controller: function($scope) {
let vm = this;
vm.$onInit = function() {
console.log("init!");
$("#theCarousel").carousel();
$("#theCarousel").on("slide.bs.carousel", (event) => {
vm.onEventTriggered();
console.log("sliding " + event.direction);
$scope.$apply();
});
};
}
using $scope.$apply()
updated plunkr : https://plnkr.co/edit/8yZOyuQfofdoYz00tFBk?p=preview
You need to use $scope.$apply(), because $("#theCarousel").on("slide.bs.carousel", ... is jquery code, and you need to notify angular about it using $scope.$apply()

How to use resolve with Angular 1.5 *components* and UI Bootstrap Modal

I am trying to pass data to a ubi modal that is an Angular 1.5 component using resolve. I know this is possible because it shows that resolve is supported for components in the uib modal documentation.
component (Type: string, Example: myComponent) - A string reference to
the component to be rendered that is registered with Angular's
compiler. If using a directive, the directive must have restrict: 'E'
and a template or templateUrl set.
It supports these bindings:
(...)
resolve - An object of the modal resolve values. See UI Router
resolves for details.
All the examples I am finding declare templateurl/controller in the open method. Then the item declared in resolve is injected into to the controller. I am passing an Angular 1.5 component to the modal (not templateurl/controller), and when I try to inject the item from resolve, I get a dreaded "unknow provider" error.
Here is my code. I am trying to pass a url.
Controller of component calling the model
ParentController.$inject = ['$uibModal'];
function ParentController $uibModal) {
var $ctrl = this;
$ctrl.openComponentModal = function(url) {
var modalInstance = $uibModal.open({
animation: false,
component: "ImageModalComponent",
resolve: {
url: function() {
return url;
}
}
});
};
}
Controller in component that is the modal
ImageModalController.$inject = ['url'];
function ImageModalController(url) {
var $ctrl = this;
$ctrl.$onInit = function() {
console.log(url);
};
}
For components, resolve needs to be added to the bindings, then it is available on the isolated scope. In other words, add resolve: '<' when declaring the component.
Modal Component
var template = require('./image_modal.component.html');
var ImageModalController = require('./image_modal.controller');
module.exports = {
template: template,
bindings: {
close: '&',
resolve: ‘<‘
},
controller: ImageModalController
};
Controller of component calling the model
ParentController.$inject = ['$uibModal'];
function ParentController $uibModal){
var $ctrl = this;
$ctrl.openComponentModal = function (urlFromClickEvent) {
var modalInstance = $uibModal.open({
animation: false,
component: "ImageModalComponent",
resolve: {
url: function() {
return url;
}
}
});
};
}
Controller of component that is the modal
ImageModalController.$inject = [];
function ImageModalController() {
var $ctrl = this;
$ctrl.$onInit = function () {
console.log($ctrl.resolve.url);
};
}

Pass object to component

I have created a component that needs to have a reference to the object for which the component was created. I didn't make to work and all my trials have failed. Below, I try to describe the intention.
The component definition would maybe look like this:
angular
.module('myModule')
.component('myComponent', {
templateUrl: "template.html",
controller: [
MyController
],
bindings: {
myObject: '='
}
});
function MyController(myObject) {
var vm = this;
vm.myObject = myObject;
}
In a service I would like to create my object like this:
function createMyObject(args) {
var myObject = {some: data};
myObject.ref = "<my-component myObject='{{myObject}}'></my-component>";
return myObject;
}
Question
How can I pass data to angular component tag? Do I have to switch back to a component directive to make it work?
Any ideas are greatly appreciated. Thank you.
Solution 1
In your template:
<my-component key='$ctrl.myObject'></my-component>
In code:
angular
.module('myModule')
.component('myComponent', {
templateUrl: "template.html",
controller: [
'objectService'
MyController
],
bindings: {
key: '=' // or key: '<' it depends on what binding you need
}
});
function MyController(myObject, objectService) {
var vm = this;
vm.myObject.whatever(); // myObject is assigned to 'this' automatically
}
Solution 2 - via Component Bindings
Component:
angular
.module('myModule')
.component('myComponent', {
templateUrl: "template.html",
controller: [
'objectService'
MyController
],
bindings: {
key: '#'
}
});
function MyController(myObject, objectService) {
var vm = this;
vm.myObject = objectService.find(vm.key);
}
Usage:
function createMyObject(args) {
var myObject = {key: ..., some: data};
myObject.ref = "<my-component key='" + myObject.key + "'></my-component>";
return myObject;
}

Resources