AngularJS Components - How do I pass in a back end variable? - javascript

I'm trying to component-ise my codebase and have come up stuck on this problem.
When using $scopes and Controllers I would pass a server token to my rest call method with ng-init. Trying to do the same with a Component is not working.
javascript
angular
.module('myApp', [])
.controller('mainCtrl', function() {
var self = this;
self.options = function() {
var o = {}
o.token = self.serverToken
return o;
}
self.restData = {
url: 'http://rest.url',
options: self.options()
}
})
.component('myComponent', {
bindings: {
restData: '<'
},
template: '<p>template, calls child components</p>',
controller: function(restService) {
this.callRestService = function() {
restService.get(this.restData.url, this.restData.options)
}
console.log(this.restData.url) // http://rest.url
console.log(this.restData.options) // {token: undefined}
}
})
html
<html ng-app="myApp">
<!-- head -->
<body ng-controller="mainCtrl as m" ng-init="m.serverToken='12345'">
<my-component rest-data="m.restData"></my-component>
</body>
</html>
How do I pass the value to the component?

The issue is that the ng-init is executed after the controller is instantiated. However you are creating your restData object during the construction of your controller at which time the serverToken is undefined.
You could build your restData object after ng-init is called with something like this:
.controller('mainCtrl', function() {
var self = this;
self.restData = {};
self.init = function(token) {
self.serverToken=token;
self.restData = {
url: 'http://rest.url',
options: {token:token}
};
};
})
Your component can then do something when that restData changes. For example:
.component('myComponent', {
bindings: {
restData: '<'
},
template: '<p>template, calls child components</p>',
controller: function(restService) {
this.callRestService = function() {
restService.get(this.restData.url, this.restData.options)
}
this.$onChanges = function(changes) {
console.log(this.restData) // http://rest.url
console.log(this.restData.options) // {token: 12345}
this.callRestService();
}
}
});
The HTML would change to call your init method:
<body ng-controller="mainCtrl as m" ng-init="m.init(12345)">
<my-component rest-data="m.restData"></my-component>
</body>

Related

Unable to bind some data between components?

I am computing/building a javascript object in a directive (component) and I want to pass it to another component.
In my case, I am referring to the list of heroes that that is in the heroList.js (which is the source component), and I want to transfer the passingObject to the someOtherTabPage.js (which is the destination component).
This is the link to my plunk. Can you please help with this problem, I don't what's wrong in binding the passingObject to between my two components?
(function(angular) {
'use strict';
function someOtherTabPageController($scope) {
//do some work with the passingObject
alert(JSON.stringify(passingObject));
}
angular.module('heroApp').component('someOtherTabPage', {
templateUrl: 'someOtherTabPage.html',
controller: someOtherTabPageController,
bindings :{
passingObject: '='
}
});
})(window.angular);
To achieve what you need with the same architecture you can use the $rootScope to pass the data between your controllers. Here is the updated code :
(function(angular) {
'use strict';
function someOtherTabPageController($scope,$rootScope) {
var ctrl = this;
//do some work with the passingObject
alert($rootScope.passingObject);
}
angular.module('heroApp').component('someOtherTabPage', {
templateUrl: 'someOtherTabPage.html',
controller: someOtherTabPageController,
bindings :{
passingObject: '='
}
});
})(window.angular);
(function(angular) {
'use strict';
function HeroListController($scope, $element, $attrs,$rootScope) {
var ctrl = this;
// This would be loaded by $http etc.
ctrl.list = [
{
name: 'Superman',
location: ''
},
{
name: 'Batman',
location: 'Wayne Manor'
}
];
ctrl.create = function(hero) {
ctrl.list.push(angular.copy(hero));
};
ctrl.updateHero = function(hero, prop, value) {
hero[prop] = value;
};
ctrl.deleteHero = function(hero) {
var idx = ctrl.list.indexOf(hero);
if (idx >= 0) {
ctrl.list.splice(idx, 1);
}
};
$scope.passingObject = ctrl.list;
$rootScope.passingObject = ctrl.list;
}
angular.module('heroApp').component('heroList', {
templateUrl: 'heroList.html',
controller: HeroListController,
bindings: {
onCreate: '&'
}
});
})(window.angular);
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example - example-heroComponentTree-production</title>
<script src="//code.angularjs.org/snapshot/angular.min.js"></script>
<script src="index.js"></script>
<script src="heroList.js"></script>
<script src="heroDetail.js"></script>
<script src="editableField.js"></script>
<script src="someOtherTabPage.js"></script>
</head>
<body ng-app="heroApp">
<hero-list></hero-list>
<some-other-tab-page></some-other-tab-page>
</body>
</html>
I think the way you're meant to grab the passingObject in the controller, after it has been bound by the component is via the this keyword
function someOtherTabPageController($scope) {
var ctrl = this;
//do some work with the passingObject
alert(JSON.stringify(ctrl.passingObject));
}
You can see the same principle applied in your example plunk in heroDetail.js in the HeroDetailController
EDIT to address last comment: 'passingObject is undefined'
My first guess would be that the component wasn't passed the passingObject in the instantiation. The right way would look like this:
<some-other-tab-page passing-object="someObjectHere"></some-other-tab-page>

How to use bound values in a components controller

I have a component that looks like this:
var meadow = angular.module('meadow');
meadow.component('productIncome', {
bindings: {
product: '='
},
templateUrl: '/static/js/app/product-detail/product-income/product-income.html',
controller: function () {
var vm = this;
console.log(vm.product)
}
})
Now I want to make us of the product that's bound to the component, but it's telling me that "vm.product is undefined". I've tried using $onInit but it still produces the same results. For $onInit it did :
vm.$onInit = function(){
console.log(vm.product)
}
product-income.html
<product-income product="$ctrl.products.product"></product-income>
How can I get this working? Thanks
I made a working demo here:
var meadow = angular.module('meadow', []);
meadow = meadow.controller("abc", function($scope) {
$scope.products = {
product: "a"
}
});
meadow.component('productIncome', {
bindings: {
product: '='
},
template: "<div></div>",
controller: function() {
var vm = this;
vm.$onChanges = function() {
console.log("onchange", vm.product);
}
setTimeout(function() {
console.log("timeout", vm.product);
});
}
})
<script src="https://code.angularjs.org/1.6.3/angular.min.js"></script>
<div ng-app="meadow" ng-controller="abc">
<product-income product="products.product"></product-income>
</div>
So it seems that the order of the controllers are not sure, u should make a async to get the value, or use "$onChanges " to listen to the value.

why the factory is not able to access inside the controller

I have created notification factory and pass inside controller,Inside controller when assign the factory to the scope getting error.
alertsManager
MyApp.factory('alertsManager', function() {
return {
alerts: {},
addAlert: function(message, type) {
this.alerts[type] = this.alerts[type] || [];
this.alerts[type].push(message);
},
clearAlerts: function() {
for(var x in this.alerts) {
delete this.alerts[x];
}
}
};
});
var LoginController = function($scope,$rootScope,alerts,alertsManager)
{
$scope.alerts = alertsManager.alerts;
// getting error.
**angular.js:11594 TypeError: Cannot read property 'alerts' of undefined**
}
LoginController.$inject = ['$scope', '$rootScope','alerts','alertsManager'];
**why factory not able to access inside controller.*
Try something like below .
code:
var myApp = angular.module('myApp', []);
myApp.factory('alertsManager', function() {
return {
alerts: {'alert':"i'm from factory service"},
addAlert: function() { //code },
clearAlerts: function() { //code }
}
});
myApp.controller('MyCtrl',['$scope','alertsManager', function($scope, alertsManager) {
$scope.test = alertsManager.alerts.alert;
}]);
Note : Inject factory service into Controller
working sample here .
No need to inject 'alerts' as a dependency in controller.
Sorry ..very stupid question .. Are you sure Do you include these files in Index.html?
like this:
<script src="app/services/alertsManager.js"></script>

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>

pass variable from ng-grid Angulars.js

I'm tring to to use a variable from a ng-grid table in another controller,
A part of my ng-grid is defined like this:
app.controller('ng-grid-controller'){
....
$scope.gridOptions = {
data:MyData,
columnDefs: [
{field:'_id'},{name:'name',cellTemplate: 'templates/show.html'}]
};
$scope.getDetail = function(_id){
alert(_id);
var test=_id;
console.log(test);
return test;
};
}
I'm able to show the displayed value in my template show.html like this:
<div ng-style="{'cursor': row.cursor}" ng-click="getDetail(row.getProperty('_id'));" data >
</div>
But my question is how I can access this value inside another controller,I need to pass for example to pass this value as parameter for another template:
In my route I have something like that:
when('/show/:thatValue', {// Here I want that value I display=thatValue
templateUrl: 'templates/displayvalue.html',
controller: 'ShowController'
}).
And in my controller:
app.controller('ShowController', function($scope) {
$scope.value='the value I display';//Something like this
});
When you need to share data between controllers it's best to use a service then you can inject that value into your respective controllers. For example:
app.factory('SomeService', [ '$log', function($log) {
return {
variable: null,
getVariable: function() {
return this.variable;
},
setVariable: function(value) {
this.variable = value;
}
};
}]);
Then to use this in your Controller:
app.controller("MyController", [ '$scope', 'SomeService', function($scope, SomeService) {
$scope.someMethod = function() {
$scope.variable = SomeService.getVariable();
};
$scope.setSomeService = function(value) {
SomeService.setVariable( value );
}
}];

Categories

Resources