ui-router, factory share data - angularjs

Hy,
I want to share data between 1 component (NavBar) and other 1 ctrl (Ctrl1) in ui-view with factory, but it's not work.
When i modify factory in component or ctrl, it modify only his own scope. I want to share factory between ctrl and component.
HTML :
<div ng-app="myApp">
<global-component></global-component>
</div>
Javascript :
var myApp = angular.module('myApp', [ 'ui.router']);
myApp.config(function ($stateProvider, $urlRouterProvider){
$stateProvider.state("state1", {
url: "#",
template: "<p>State 1 </p> <input type=\"text\" ng-model=\"vm.b\"/> {{vm.b}}",
controller: "Ctrl1",
controllerAs: 'vm'
});
$urlRouterProvider.otherwise(function($injector, $location) {
$injector.get('$state').go("state1");
});
});
//Global Component
myApp.component('globalComponent', {
template: 'Global controler </br> <nav-bar></nav-bar> <div ui-view></div>',
controller: "GlobalCtrl",
controllerAs: 'vm'
});
myApp.controller('GlobalCtrl',function(Data){
Data.test="test1";
});
//NavBar
myApp.component('navBar', {
template: 'NavBar <input type=\"text\" ng-model=\"vm.a\"/> {{vm.a}}',
controller: "NavBarCtrl",
controllerAs: 'vm'
});
myApp.controller('NavBarCtrl',function(Data){
var vm=this;
vm.a=Data.test;
});
myApp.controller('Ctrl1',function(Data){
var vm=this;
Data.test="titi";
vm.b=Data.test;
});
myApp.factory('Data', function(){
var data={};
data.test="";
return data;
});
The code :
https://codepen.io/anon/pen/YrdvbV?editors=1111
Thanks

Check out working solution here.
The reason why it's wasn't working in the first palce is that you have changed the reference to data in your setData method. When the reference is changed, your are not working with the same object as before so this vm.a=Data.getData(); is not bound to the same object as on initialization.
In your case, one way to resolve this is to wrap an object around your data (in the example provided, I used data.item instead of just data). Other options are to use $watch or something similar so values could be rebound to ng-model.

Related

Trouble connecting controller using routing in AngularJS

Ill try and do my best to explain...
It doesn't seem like my controller is connecting/working properly. I'm not sure exactly why, every time I check my syntax seems correct. Here is my route declaration:
angular.module('portfolio', ['ngRoute']).config(function ($routeProvider, $locationProvider) {
$routeProvider.when('/', {
templateUrl: '/public/app/views/main.html',
controller: 'MainCtrl',
controllerAs: 'main'
}).when('/about', {
templateUrl: '/public/app/views/about.html',
controller: 'AboutCtrl',
controllerAs: 'about'
}).when('/Resume', {
templateUrl: '/public/app/views/resume.html',
controller: 'ResumeCtrl',
controllerAs: 'Resume'
}).when('/Samples', {
templateUrl: '/public/app/views/samples.html',
controller: 'SamplesCtrl',
controllerAs: 'Samples'
}).otherwise({
redirectTo: '/'
});
$locationProvider.html5Mode(false).hashPrefix('');
});
Just as an example here is my resume view:
<paper-button ng-click="changeEx()" raised>Experience</paper-button>
<paper-button ng-click="changeSkills()" raised>Skills</paper-button>
<paper-button ng-click="changeEdu()" raised>Education</paper-button>
<paper-button ng-click="changeMisc()" raised>Misc.</paper-button>
<div ng-hide="exp">
<p>Experience</p>
</div>
<div ng-show="skills">
<p>Skills</p>
</div>
<div ng-show="education">
<p>Education</p>
</div>
<div ng-show="misc">
<p>Misc.</p>
</div>
Finally, here is the declaration of the controller for the resume view:
angular.module('portfolio', []).controller('ResumeCtrl', function () {
this.exp = true;
});
Obviously, this controller is incomplete but I am simply trying to test it by using this variable.
Do not use square brackets when you are referencing a module that has already been declared. This is interpreted by Angular as declaring a new module:
angular.module('portfolio').controller('ResumeCtrl', function () {
this.exp = true;
});
The next thing I would check is your main HTML page. Do you have this directive somewhere on your page:
<div ng-view></div>
Another problem is that you are declaring controllerAs in your route as Resume, but you are using this.exp to assign your variable and also trying to reference exp in your view. You need to follow this pattern instead, or use $scope:
angular.module('portfolio').controller('ResumeCtrl', function () {
var Resume = this;
Resume.exp = true;
});
And in your view you should reference the variable using the same name you defined in controllerAs:
<div ng-hide="Resume.exp">
<p>Experience</p>
</div>
Or, alternatively, you can keep your view the same, but assign your variable using $scope:
angular.module('portfolio').controller('ResumeCtrl', function ($scope) {
$scope.exp = true;
});

angularjs - ng-show does not woking

I use ng-show to show or hide navigator.
In index.html :
<div class="container" ng-show="vm.error" nav></div>
In app.js
var siteApp = angular.module('siteApp', ['ngRoute']);
siteApp.config(function($routeProvider) {
$routeProvider
.when('/', {
controller: 'HomeController',
controllerAs: 'vm',
templateUrl: '/home.html'
})
.when('/404', {
controller: 'ErrorController',
controllerAs: 'vm',
templateUrl: '/404.html'
});
});
In HomeController.js
siteApp.controller('HomeController', function(){
var vm = this;
vm.error = false;
vm.message = "Halu home page";
});
In ErrorController.js
siteApp.controller('ErrorController', function(){
var vm = this;
vm.error = true;
vm.message = "Error 404";
});
My navigator hides in both of pages although vm.message show true. Why ?
You can help me at : https://github.com/ryantranvn/mean
As this SO answer discusses regarding using this in place of $scope:
When using this style, directives should use the controllerAs property in their return object per the Directive documentation.
A quick workaround for you would be to preface variable names with $scope if you want them to be available in the view:
siteApp.controller('HomeController', function(){
$scope.error = false;
$scope.message = "Halu home page";
});
<div class="container" ng-show="error" nav>{{message}}</div>
As to why the text was being hidden in both your test cases, the variable being used in ng-show was not defined.
Since you are using "this" in the controller function, you will have to declare your Controller with "as" syntax.
If you are using routes to bind the controller, add below code in routes
controller: "HomeController",
controllerAs: "HomeCtrl"
Or if you are directly writing ng-controller in html, use below code
<div ng-controller="HomeCtrl as HomeController">
<div class="container" ng-show="HomeCtrl.error" nav></div>
</div>

The controller with the name 'complatedtabs' is not registered

my controller
(function() {
'use strict';
angular
.module('portfolio')
.controller('completedTabsController', completedTabsController);
function completedTabsController($scope){
$scope.go = function(){
alert("hi");
};
}
})();
my html
<button class="primary-btn add-offline pull-right" ng-click="completedTabsCtrl.openOfflineDealForm()">Add Offline Deal</button>
my module.js
$stateProvider
.state('dashboard.portfolio.complatedtabs', {
url: '/complatedtabs',
templateUrl: PORTFOLIO_URL + '/complatedtabs/complatedtabs.tpl.html',
controller: 'complatedtabs',
controllerAs: 'completedTabsCtrl'
});
But it showing this error
The controller with the name 'complatedtabs' is not registered.
How i will fix this??
Controller name should be from what you registered with controller method. Try like below.
$stateProvider
.state('dashboard.portfolio.complatedtabs', {
url: '/complatedtabs',
templateUrl: PORTFOLIO_URL + '/complatedtabs/complatedtabs.tpl.html',
controller: 'completedTabsController',
controllerAs: 'completedTabsCtrl'
});
If You are confused and wanted make sure by listing all the registered controllers. Use below code which will give you all the registered controllers and this is a test code.
// Test Code
var appModule = angular.module('myApp',[]);
angular.module('myApp').controller('MainCtrl', function($scope) {
$scope.controllers = appModule._invokeQueue.filter(function(el){
return el[0] === "$controllerProvider";
}).map(function(el){
return el[2]["0"];
});
});
angular.module('myApp').controller('TestCtrl', function(){});
angular.module('myApp').controller('TestCtrl2', function(){});
Controller name in the route declaration (complatedtabs) does not match the controller name in its definition (completedTabsController): you should have the same name in both, for instance just change the controller to:
.controller('complatedtabs', completedTabsController);
Please also note a possible typo: complAtedtabs

Controller loaded twice using ui-router + custom directive

I am trying to bring to my homepage a custom directive which will print me some output.
In the network tab in my devtools I just saw that my controller loads twice.
controller:
var homeController = function($log,leaguesFactory){
var self = this;
self.leagues = [];
leaguesFactory.loadLeagues()
.then(function(leagues){
self.leagues = leagues.data.Competition;
});
self.message= 'test message';
};
directive:
var leaguesTabs = function(){
return {
restrict : 'E',
templateUrl : 'app/home/leagues-tabs.tpl.php',
scope: {
leagues: '='
},
controller: 'homeController',
controllerAs: 'homeCtrl'
};
};
ui-router states:
$stateProvider
.state('home',{
url : '/',
templateUrl : 'app/home/home.tpl.php',
controller : 'homeController',
controllerAs: 'homeCtrl'
})...
I just want to use my homeCtrl in the directive, but it seems that the state provider loads it also and make it load twice. If I remove the controller from the directive then I don't get access to the homeCtrl, if I remove the homeCtrl from the stateprovider than I don't have access in the home.tpl.php
home.tpl.php:
<div>
<leagues-tabs></leagues-tabs>
</div>
any idea?
Actually problem related to next steps:
ui-router start handling url '/'
ui-router create an instance of 'homeController'
ui-router render the view 'app/home/home.tpl.php'
Angular see usage a custom directive - 'leagues-tabs'
'leagues-tabs' directive create an instance of 'homeController'
'leagues-tabs' render the view 'app/home/home.tpl.php'
You can follow any of next possible solutions:
Change controller for 'leagues-tabs' to something special
Remove controller usage from ui-router state definition
You can try this one http://plnkr.co/edit/LG7Wn5OGFrAzIssBFnEE?p=preview
App
var app = angular.module('app', ['ui.router', 'leagueTabs']);
UI Router
app.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/leagues');
$stateProvider
.state('leagues', {
url: '/leagues',
templateUrl: 'partial-leagues.html',
controller: 'LeaguesController',
controllerAs: 'ctrl'
});
}]);
Controller
app.controller('LeaguesController', ['$http', function($http) {
var self = this;
$http.get('leagues.json').success(function(data){
self.leagues = data;
})
}]);
View
<div>
<league-tabs leagues="ctrl.leagues"></league-tabs>
</div>
Directive
var leagueTabs = angular.module('leagueTabs', []);
leagueTabs.directive('leagueTabs', function(){
return {
restrict : 'E',
templateUrl : 'partial-league-tabs.html',
scope: {
leagues: '='
},
controller: 'LeagueTabsController',
controllerAs: 'leagueTabs'
}
});
leagueTabs.controller('LeagueTabsController', function($scope){
var self = this
$scope.$watch('leagues', function(leagues){
self.leagues = leagues;
})
})
Directive View
<div>
<ul ng-repeat="league in leagueTabs.leagues">
<li>{{league.name}}</li>
</ul>
</div>

Can't access value of scope in AngularJS. Console log returns undefined

I'm using ui-router for my application and nesting controllers within ui-view. My parent controller looks like this:
'use strict';
angular.module("discussoramaApp").controller("mainController", ["RestFullResponse", "Restangular", "localStorageService", "$scope", function(RestFullResponse, Restangular, localStorageService, $scope){
var currentId = localStorageService.get("***");
var user = Restangular.one("users", currentId);
var Profile = user.get({}, {"Authorization" : localStorageService.get('***')}).then(function(profile) {
$scope.profile = profile;
});
}]);
And my child controller:
'use strict';
angular.module("discussoramaApp").controller("getTopicsController", ["RestFullResponse", "Restangular", "localStorageService", "$scope", function(RestFullResponse, Restangular, localStorageService, $scope){
var topics = Restangular.all('topics');
var allTopics = topics.getList({},{"Authorization" : localStorageService.get('***')}).then(function(topics){
$scope.topics = topics;
});
console.log($scope); // this works
console.log($scope.profile); // this returns undefined
}]);
The problem I'm having is getting the inherited $scope value for profile in the child controller. When I log $scope, profile is clearly visible in the console.
But when I try to log $scope.profile the console returns undefined. Any ideas?
Edit: Adding my ui-router config.
angular.module("discussoramaApp").config(
function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise('/home');
$urlRouterProvider.when('', '/home');
$stateProvider
.state('main',{
url: '',
templateUrl: 'partials/main.html',
requireLogin: true
})
.state('main.home',{
url: '/home',
templateUrl: 'partials/main.home.html',
requireLogin: true,
title: 'Home'
});
}
);
And the corresponding html files:
// main.html
<div ng-controller="mainController">
<div class="container">
<div ui-view></div>
</div>
</div>
and the child html partial:
// main.home.html
<div ng-controller="getTopicsController">
<div ng-repeat="topic in topics | filter:search">
<a ui-sref="main.topic({id: topic.id})">{{ topic.topic_title }}</a>
</div>
</div>
UPDATE: Solved this with a watcher set up like this in the child controller. Thanks #jonathanpglick and #Nix for the help.
$scope.$watch('profile', function(profile) {
if(profile) {
$window.document.title = "Discussorama | " + profile.user.name;
}
});
$scope.profile is being set after an asynchronous request so I suspect that the second controller is being instantiated before user.get() returns and assigns a value to $scope.profile.
I think you'll want to set up a watcher (like $scope.$watch('profile', function(profile) {});) in the child controller so you can do things when the profile becomes available or changes.
Also, the reason you can see the profile key on $scope when you console log $scope can be explained here: https://stackoverflow.com/a/7389177/325018. You'll want to use console.dir() to get the current state of the object when it's called.
UPDATE:
I just realized you're using the ui-router and so there's an even easier way to do this. The ui-router has a resolve object that you can use to dependency inject things like this into your controller. Each resolve function just needs to return a value or a promise and it will be available for injection into the controller with resolve key name. It would look like this for you:
angular.module("discussoramaApp").config(
function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise('/home');
$urlRouterProvider.when('', '/home');
$stateProvider
.state('main',{
url: '',
templateUrl: 'partials/main.html',
requireLogin: true,
resolve: {
profile: ['Restangular', 'localStorageService', function(Restangular , localStorageService) {
var currentId = localStorageService.get("***");
var user = Restangular.one("users", currentId);
return user.get({}, {"Authorization" : localStorageService.get('***')});
}
}
})
.state('main.home',{
url: '/home',
templateUrl: 'partials/main.home.html',
requireLogin: true,
title: 'Home'
});
}
);
angular.module("discussoramaApp").controller("mainController", ["profile", "$scope", function(profile, $scope){
$scope.profile = profile;
}]);
Just because you have nested scope, doesn't mean it will wait for user.get() to return before instantiating your nested getTopicsController.
Your issue is:
mainController controller initializes and calls user.get()
getTopicsController initializes and logs console.log($scope.profile)
The call to user.get() returns and then sets on scope.
This is a common issue, if you need to gaurantee that $scope.profile is set, use resolve or watch the variable.
I actually gave an example of how to do this earlier today: AngularJS $rootScope.$broadcast not working in app.run

Resources