Having a hard time inheriting scope from parent in AngularJS - angularjs

So I have the following two controllers, a parent and a child, and I need a value that is dynamically added to the parent scope passed on into the child scope. I really can't understand how the service injection works either. Here is my parent controller:
'use strict';
angular.module("myApp").controller("singleTopicController", ["RestFullResponse", "Restangular", "localStorageService", "$scope", "$window", "$stateParams", function(RestFullResponse, Restangular, localStorageService, $scope, $window, $stateParams){
var topics = Restangular.one('topics', $stateParams.id);
var Topics = topics.get({},{"Authorization" : localStorageService.get('***')}).then(function(topic){
$scope.topic = topic;
$scope.topic.id = topic.id;
$window.document.title = 'Example | ' + $scope.topic.topic_title;
console.log($scope.topic);
});
}]);
And my child controller which needs the topic.id to work.
'use strict';
angular.module("myApp").controller("commentSingleController", ["RestFullResponse", "Restangular", "localStorageService", "$scope", "$state", "$stateParams", "$timeout", function(RestFullResponse, Restangular, localStorageService, $scope, $state, $stateParams, $timeout){
$scope.topic = {};
var oneTopic = Restangular.one('topics', $scope.topic.id);
oneTopic.get({}, {"Authorization" : localStorageService.get('***')}).then(function(topic) {
topic.getList('comments', {}, {"Authorization" : localStorageService.get('***')}).then(function(comments){
$scope.comments = comments;
console.log($scope.comments);
});
});
$scope.isCollapsed = true;
var comments = Restangular.all('comments');
$scope.commentData = {
//topic_id: $scope.parent.topic.id
};
$scope.postComment = function(mood) {
$scope.commentData.mood = mood;
comments.post($scope.commentData, {}, {"Authorization" : localStorageService.get('***')}).then(function(response){
$state.transitionTo($state.current, $stateParams, {
reload: true,
inherit: false,
notify: true
});
}, function(response){
$scope.error = response.data.message;
})
};
}]);
If I add
console.dir($scope.$parent);
to the child controller, topic is obviously there.
But if I try
console.dir($scope.$parent.topic);
I get undefined.
I tried wrapping the Restangular.get() of the child controller in a watcher but that didn't do anything.
$scope.$watch('topic', function{
Restangular.one() ...})
Where am I going wrong here.
<div class="main-left-column">
**<div ng-controller="singleTopicController">** //my main controller
<div class="topic-full">
<div class="topic-left">
<div class="topic-left-inner">
<a ui-sref="main.topic({id: topic.id})"><h4>{{ topic.topic_title }}</h4></a>
<hr>
<img ng-src="{{ topic.image_url }}" class="img-responsive img-topic" tooltip="{{ topic.topic_title}}"/>
<hr ng-if="topic.image_url">
<p>{{ topic.topic_content }}</p>
</div>
</div>
<div class="topic-right">
**<div class="topic-right-inner" ng-controller="commentSingleController">** //child controller
<img ng-src="{{ topic.profile_pic }}" width="60px" class="profile-pic"/>
<div class="topic-data">
<h4 class="topic-data">{{ topic.author_name }}</h4>
<h5 class="topic-data">- posted on {{ topic.created_at }}</h5>
</div>
<div class="comment-count">
<div class="comment-count-mood red" tooltip="Negative comments"><p>{{ topic.comments_angry }}</p></div>
<div class="comment-count-mood yellow" tooltip="Neutral comments"><p>{{ topic.comments_sad }}</p></div>
<div class="comment-count-mood green" tooltip="Positive comments"><p>{{ topic.comments_happy }}</p></div>
</div>
<div class="clear"></div>
<hr>
<p ng-if="comments.length == 0">No comments</p>
<div class="line-through">
<div ng-repeat="comment in comments">
<div class="comment-left">
<img ng-src="{{ comment.profile_pic }}" width="40px" class="comment-pic"/>
<div class="comment-mood" ng-class="{'red': comment.mood == 2, 'yellow': comment.mood == 1, 'green': comment.mood == 0}"></div>
</div>
<div class="comment-right">
<h4 class="comment-data">{{ comment.author_name }}</h4>
<p>{{ comment.comment }}</p>
</div>
<div class="clear"></div>
<hr class="dotted" ng-if="!$last">
</div>
</div>
</div>
</div>
<div class="clear"></div>
</div>
</div>
</div>
UPDATE: Added HTML. Controller wrappers are in asterisks.

Your topic won't be created until your .get in your parent controller resolves, which is probably after the initialisation of the child controller.
If you remove the $scope.topic = {} from the child controller and add a $watch for topic.id you should be able to use the id in there.
Really you shouldn't need $scope.$parent as $scope should have everything the parent does unless it's been hidden by something in the child scope or there's an isolate scope in the way (there isn't in this case).

Related

How to get param from one controller to another?

My question is best explained when I straight go to the code.
HTML part:
<div class="panel panel-default post" ng-repeat="post in posts">
<div class="panel-body">
<div class="row">
<div class="col-sm-2">
<a class="post-avatar thumbnail" href="/profile#/{[ post.profileID ]}">
<div class="text-center">{[ user.fullname ]}</div>
</a>
</div>
</div>
</div>
When I click on the /profile#/{[ post.profileID ]} link - it takes me to the profile page. All good here.
However, I am using ngView so I have separated it like this:
<div class="col-md-3">
<div>Some HTML stuff</div>
</div>
<div class="col-md-6">
<div ng-view></div>
</div>
<div class="col-md-3">
<div>Some HTML stuff</div>
</div>
My ngView makes use of the /profile#/{[ post.profileID ]} param and I use it to display whatever I have to display.
The problem:
I can get the profileID param in my angular controller but once I get it, how will I be able to pass it onto other controllers?
My controller looks like the below:
var profileApp = angular.module('profileApp', ['ngRoute']);
profileApp.config(function($routeProvider) {
$routeProvider
.when('/:id', {
templateUrl : 'partial/profile/feed.html',
controller : 'mainController'
})
.when('/posts:id', {
templateUrl : 'partial/profile/posts.html',
controller : 'postsController'
});
});
profileApp.controller('mainController', ['$scope', '$http', '$routeParams', function($scope, $routeParams){
console.log($routeParams.id);
}]);
profileApp.controller('postsController', ['$scope', '$routeParams', function($scope, $routeParams){
console.log($routeParams.id);
}]);
As you can see, I get get the param passed from the HTML link and use it in the mainController but how will I get the param to be a link in the col-md-3 (just like the original /profile#/{[ post.profileID ]})?
Hope this makes sense. It's has been driving me nuts!
Thanks
Why don't you just edit your partial HTML pages and put the columns in it.
For partial/profile/feed.html :
<div>
<div class="col-md-6">
<div>feed stuff</div>
</div>
<div class="col-md-3">
</div>
</div>
And partial/profile/posts.html could be :
<div>
<div class="col-md-6">
</div>
<div class="col-md-3">
<div>posts stuff</div>
</div>
</div>
So I did some research into this and I just ended up using services.
See below for the answer:
profileApp.service('globalParams', function() {
var profileID = '';
return {
getProfileID: function() {
return profileID;
},
setProfileID: function(value) {
profileID = value;
}
};
});
You then pass the service into the dependencies in the controllers, like below:
profileApp.controller('mainController', ['$scope', 'globalParams', function($scope, globalParams){
//some code
};
And you can call the functions for getting and setting the variables.

angular does not load my directive

I newly start to use angular.but I have some problem to loading my directive.
I want to load my directive as soon as page loaded.
where I load data-show directive
<div class="row">
<div class="col-md-12">
<article class="row" ng-controller="DataCtrl">
<input type="button" ng-click="getDataList()" >
<h1>Some Content Here</h1>
<ul id="home" bread-crumbs></ul>
<ul class="thumbnails">
<li ng-repeat="data in list" class="col-md-5">
<show-data data="data"/>
</li>
</ul>
</article>
</div>
</div>
showData directive:
app.directive('showData', function () {
return{
restrict: 'E',
replace:true,
templateUrl: 'views/directives/datas.directive.html',
scope: {
data: "="
},
controller:'DataCtrl'
}
})
and template I used in:
<div class="well hoverwell">
<div class="row">
<h2 class="col-md-4">{{data.name}}</h2>
</div>
<div class="row">
<span class="col-md-1">Code:</span>
<span class="col-md-1">{{data.id}}</span>
</div>
<div class="row">
<span class="col-md-1">accountability:</span>
<span class="col-md-1">{{data.parent}}</span>
</div>
<div class="row">
<span class="col-md-1"> :</span>
<span class="col-md-1">{{data.definition}}</span>
</div>
</div>
and my controller
'use strict';
angular.module('app')
.controller('DataCtrl', function ($scope, DataService, $log) {
$scope.getDataList = function () {
var list = DataService.getDataList(1);
list.then(
function (result) {
$log.info(result);
$scope.dataList = result;
}, function (status) {
$log.error(status)
$scope.msg = "error " + status + " has been occur,please report to admin ";
});
};
});
and when I run my app it does not work .
when I watch it in chorome development tools my directive is comment
what is my problem.How can I call this directive as soon as page load.
thx
As you already noticed, you see empty list because your dataList in ng-repeat is not filled yet.
But you have some errors in your code:
First of all - you should never use one controller twice. So you need to create separate controller for your directive.
replace directive parameter is deprecated, better not to use it.
In your DataCtrl you set the dataList variable: $scope.dataList = result;, but in HTML you refer to list variable: <li ng-repeat="data in list" class="col-md-5">.
Maybe that example will help you to figure out with your code.

How do we call the child controller when parent controller ng-click directive called?

I am new to angular js and the following code am using in my project here my problem is when i click on ng-click=addtocart(parameter) it is not responding the child controller.?how can i call the child controller ?please help me out?
<div ng-app="" ng-controller="parentCtrl">
<ul>
<li ng-click="search('12345');">
<div >
<div>
<div><img src="ProfileImges/menu.jpg"/></div>
<div>Hello</div>
</div>
</div>
</li>
</ul>
<div ng-repeat="x in names">
<div ng-click="addToCart('SMN1');">
<div>
<h4> {{ x.Price }} per meal</h4>
<img ng-src="{{x.ImgSrc}}"/>
</div>
<div>
<img ng-src="{{x.UserImg}}"/>
<p><strong>{{x.Uname}}</strong><br>
<span>{{x.RewPer}} </span><br>
</p>
</div>
<h4>{{x.Mtitle}}</h4>
<span><strong>{{x.Cuisine}}</strong></span>
<p`enter code here`>{{x.Mdesc}}</p>
</div>
</div>
<div ng-controller="childCtrl">
<div>{{cartdetails.name }}</div>
<div>Price</div>
</div>
</div>
<script>
var sj=angular.module('MyApp', []);
sj.controller('parentCtrl', ['$scope','$http', function($scope, $http) {
$scope.search = function(param) {alert("enter123");
$http.get('AngularJs-Response.jsp?mid='+param).success(function(response) {
$scope.names = response;
});
};
$scope.addToCart=function(smid){
CallAddCart(smid);
};
}]);
function CallAddCart(smid) {
sj.controller('childCtrl', ['$scope','$http', function($scope, $http) {
$http.get('reponse.jsp?smid='+smid).success(function(response) {alert(response);
$scope.cartdetails = response;
});
}]);
};
</script>
See plnkr: http://plnkr.co/edit/IdsHc19xBUalZoIXPE2T?p=preview
In a nutshell, you can communicate from parent to child controller by using the $scope as an event bus via the $broadcast and $on APIs:
angular.module("app", [])
.controller("ParentCtrl", function($scope) {
$scope.parentName = "parent";
$scope.onClick = function() {
$scope.parentName = "clicked";
$scope.$broadcast('onSearch', {myMsg: "hi children"});
}
})
.controller("ChildCtrl", function($scope) {
$scope.childName = "child";
$scope.$on('onSearch', function(event, obj) {
$scope.childName = obj.myMsg;
})
});
After onClick() is called on the parent, the parent $broadcasts the 'name' on the 'onSearch' channel to all its children. ChildCtrl is configured to listen on the 'onSearch' channel, once it receives a message, the callback function executes.

How do I target just one instance of a nested repeat?

This is probably pretty basic, but I'm going round in circles.
I have a nested controller in a ng-repeat - I would like to trigger an event in an instance of the repeat that will affect only the nested controller in that instance, not the nested controller in all instances.
Here is a basic example to try and make things clearer:
<div ng-controller="PostsCtrl">
<div ng-repeat="post in posts">
<p>{{post.body}}</p>
<div ng-controller="CommentsCtrl">
<div ng-repeat="comment in comments">
<p>{{comments.body}}</p>
<a href ng-click="showComments(post.id)">Show comments</a>
</div
</div>
</div>
</div>
angular.module('myApp')
.controller('PostsCtrl', function ($scope, Restangular) {
var posts = Restangular.all('posts');
posts.getList().then(function(posts) {
$scope.posts = posts;
});
$scope.showComments = function(id) {
$scope.$broadcast('SHOW_COMMENTS', id);
};
});
angular.module('myApp')
.controller('CommentsCtrl', function ($scope, Restangular) {
$scope.$on('SHOW_COMMENTS', function(event, id) {
var post = Restangular.one('posts', id);
post.get().then(function(post) {
$scope.comments = post.comments;
});
});
});
What would happen in this example is that all instances of the comments controller would be populated with the same comments - I just need to be able to target the relevant one. I'm sure I'm missing something pretty fundamental, and probably going about this the wrong way.
Many thanks.
You're broadcasting "SHOW_COMMENTS" to all repeated posts. You need to isolate the scope per Post.
Isolate the scope using ng-controller="PostCtrl".
<div ng-controller="PostsCtrl">
<div ng-repeat="post in posts" ng-controller="PostCtrl">
<p>{{post.body}}</p>
<div ng-controller="CommentsCtrl">
<div ng-repeat="comment in comments">
<p>{{comments.body}}</p>
<a href ng-click="showComments()">Show comments</a>
</div
</div>
</div>
</div>
Move show comments from PostsCtrl to PostCtrl.
angular.module('myApp')
.controller('PostCtrl', function ($scope) {
$scope.showComments = function() {
$scope.$broadcast('SHOW_COMMENTS', $scope.post.id);
};
});
Do you really need to use events? You could use ng-if instead.
Your comments are embedded in each Post anyway so why request them again. In this case you could do like something this...
<div ng-controller="PostsCtrl">
<div ng-repeat="post in posts" ng-controller="PostCtrl">
<p>{{post.body}}</p>
<a href ng-click="toggleComments()">Show comments</a>
<div ng-controller="CommentsCtrl" ng-if="showComments">
<div ng-repeat="comment in post.comments">
<p>{{comments.body}}</p>
</div
</div>
</div>
</div>
Toggle comments...
angular.module('myApp')
.controller('PostCtrl', function ($scope) {
$scope.showComments = false;
$scope.toggleComments = function() {
$scope.showComments = !$scope.showComments;
};
});

AngularJS How to get data to controller via $rootScope?

I'm working on an mobile app and I'm having problems with getting data to the controller. What i do is i get the data from a service and that works well (on routing this is '/' or root directory):
var listdnModule = angular.module('listdn', []);
listdnModule.factory('getActiveDnService', ['$http', function ($http) {
return {
getActiveDnSvc: function (izvajalecID) {
return $http({ method: 'POST', url: 'svc.aspx/getActiveDN', data: "{'izvajalecID':" + "'" + izvajalecID + "'}", cache: true });
}
};
}]);
listdnModule.controller('listdnCtrl', ['$scope', '$http', 'getActiveDnService','$rootScope', function ($scope, $http, svc, $rootScope) {
$scope.mjav = 1;
svc.getActiveDnSvc($scope.mjav).success(function (data) {
$rootScope.dnlist = data.d;
$scope.listdn = data.d;
});
}]);
So this works fine. It sets the data to the rootScope and to localscope and reads it from local scope.
Then i'm linking the list of Costumers to costumerdetail. The route settings are like this:
mSvc.config(['$routeProvider',
function ($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'tmpl/listdn.html',
controller: 'listdnCtrl'
}).
when('/settings', {
templateUrl: 'tmpl/nastavitve.html',
controller: 'settings'
}).
when('/dndetail/:dnid', {
templateUrl: 'tmpl/dndetail.html',
controller: 'dndetailCtrl'
}).
otherwise({
redirectTo: '/'
});
}]);
The error comes after i try to get dndetail. I get the right ID from $routeParams but i dont get the data in the right time. The code is this:
var dndetail = angular.module('dndetail', []);
dndetail.controller('dndetailCtrl', ['$rootScope', '$scope', '$routeParams', function ($rootScope, $scope, $routeParams) {
console.log($rootScope.dnlist[0]);
$scope.datal = $rootScope.dnlist;
$scope.id = $routeParams.dnid;
for(var i = 0; i <= datal.length; i++) {
if (datal[i].ID === $scope.id) {
$scope.data = datal[i];
}
}
}]);
And this is the error i get:
As you can see the console.log gets the object and prints the output (I masked it because it's company data) while datal is undefined. The special AngularJS tab in chrome DevTools also says the data is there:
And for the end the template of the view that doesnt get data:
<ul ng-controller="dndetailCtrl" class="list-group">
<li class="list-group-item">
<div class="row info-row-li">
<div class="pull-left">Naslov</div>
<div class="pull-right">
<a ng-href="https://maps.google.com/?q={{ data.Ulica }} {{ data.Posta }} {{ data.Kraj }}">
{{ $root.dnlist[1].Ulica }}<br />
{{ data.Posta }} {{ data.Kraj }}<br />
{{ data.Drzava }}</a>
</div>
</div>
</li>
<li class="list-group-item">
<div class="row info-row-li">
<div class="pull-left">Datum izvedbe</div>
<div id="kupec-pe" class="pull-right">{{ data.DatumIzvedbe }}</div>
</div>
</li>
<li class="list-group-item">
<div class="row info-row-li">
<div class="pull-left">Datum naloga</div>
<div id="kupec-dst" class="pull-right">{{ data.DatumNaloga }}</div>
</div>
</li>
<li class="list-group-item">
<div class="row info-row-li">
<div class="pull-left">Opis:</div>
<div id="kupec-komerc" class="pull-right">{{ data.Opis }}</div>
</div>
</li>
<li class="list-group-item">
<div class="row info-row-li">
<div class="pull-left">Šifra dejavnosti:</div>
<div id="kupec-sif" class="pull-right">{{ data.sifDej }}</div>
</div>
</li>
<li class="list-group-item">
<div class="row info-row-li">
<div class="pull-left">Šifra dejavnosti:</div>
<div id="Div1" class="pull-right">{{ data.DatumIzvedbe }}</div>
</div>
</li>
</ul>
Any ideas?
UPDATE
This is the new controller:
dndetail.controller('dndetailCtrl', ['$rootScope', '$scope', '$routeParams', function ($rootScope, $scope, $routeParams) {
$rootScope.dnlist;
$scope.id = $routeParams.dnid;
for (var i = 0; i <= $rootScope.dnlist.length; i++) {
if ($rootScope.dnlist[i].ID === $scope.id) {
$scope.data = $rootScope.dnlist[i];
}
}
}]);
still doesnt work. From an array of elements i want to get one element by id and then save it to data so i can read from data. For loop doesnt get the data (unindentified dnlist) but if i bind {{ $root.dnlist[1].Property }} in the template it works.
I don't think problem is fixed by this answer and tried to delete it, I have undelete it as it has been referred in a comment.
$http in angularjs returns a promise, you can't use the promise directly to access the data, check this answer where it answer something very similar.
If anyone was wondering the problem was with the equality operator. If I change === with the one that checks type == i dont get the TypeError: Cannot read property 'ID' of undefined error any more. Since this is the solution to the problem I'd like to have an explanation also. I'm a javascript beginner to be true and if someone got an idea what happened here, I'd very much like to know the explanation.
The new controller that works:
dndetail.controller('dndetailCtrl', ['$rootScope', '$scope', '$routeParams', function ($rootScope, $scope, $routeParams) {
$rootScope.dnlist;
$scope.id = $routeParams.dnid;
for (var i = 0; i <= $rootScope.dnlist.length; i++) {
if ($rootScope.dnlist[i].ID == $scope.id) {
$scope.data = $rootScope.dnlist[i];
}
}
}]);

Resources