Problem:
In a directive nested within 3 ui-views, I can't access the values of my isolate scope. scope.values returns {} but when I console.log scope I can see all the values on the values property.
In a different app I can make this works and I converted this one to that method as well but it still doesn't work and I'm tracing the routes, ctrl's and I can't find the difference between the two.
Where I'm trying to access it from
Init App > ui-view > ui-view > ui-view > form-elements > form-accordion-on
What I'm working with:
The view
<ul class='form-elements'>
<li
class='row-fluid'
ng-hide='group.hidden'
ng-repeat='group in main.card.groups'
card='main.card'
form-element
values='values'
group='group'>
</li>
</ul>
This directive contains tons of different form types and calls their respective directives.
.directive('formElement', [function () {
return {
scope: {
values: '=',
group: '='
},
link: function(scope, element) {
l(scope.$parent.values);
element.attr('data-type', scope.group.type);
},
restrict: 'AE',
template: "<label ng-hide='group.type == \"section-break\"'>" +
"{{ group.name }}" +
"<strong ng-if='group.required' style='font-size: 20px;' class='text-error'>*</strong> " +
"<i ng-if='group.hidden' class='icon-eye-close'></i>" +
"</label>" +
"<div ng-switch='group.type'>" +
"<div ng-switch-when='accordion-start' form-accordion-on card='card' values='values' group='group'></div>" +
"<div ng-switch-when='accordion-end' form-accordion-off values='values' class='text-center' group='group'><hr class='mbs mtn'></div>" +
"<div ng-switch-when='address' form-address values='values' group='group'>" +
"</div>"
};
}])
This is the directive an example directive.
.directive('formAccordionOn', ['$timeout', function($timeout) {
return {
scope: {
group: '=',
values: '='
},
template: "<div class='btn-group'>" +
"<button type='button' class='btn' ng-class='{ active: values[group.trackers[0].id] == option }' ng-model='values[group.trackers[0].id]' ng-click='values[group.trackers[0].id] = option; toggleInBetweenElements()' ng-repeat='option in group.trackers[0].dropdown track by $index'>{{ option }}</button>" +
"</div>",
link: function(scope, element) {
console.log(scope) // returns the scope with the values property and it's values.
console.log(scope.values); // returns {}
})
// etc code ...
Closely related to but I'm using = on every isolate scope object:
AngularJS: Can't get a value of variable from ctrl scope into directive
Update
Sorry if this is a bit vague I've been at this for hours trying to figure out a better solution. This is just what I have atm.
Update 2
I cannot believe it was that simple.
var init = false;
scope.$watch('values', function(newVal, oldVal) {
if (_.size(newVal) !== _.size(oldVal)) {
// scope.values has the value I sent with it!
init = true;
getInitValues();
}
});
But this feels hacky, is there a more elegant way of handling this?
Update 3
I attach a flag in my ctrl when the values are ready and when that happens bam!
scope.$watch('values', function(newVal) {
if (newVal.init) {
getInitValues();
}
});
The output of console.log() is a live view (that may depend on the browser though).
When you examine the output of console.log(scope); scope has already been updated in the meantime. What you see are the current values. That is when the link function is executed scope.values is indeed an empty object. Which in turn means that values get updated after the execution of link, obviously.
If your actual problem is not accessing values during the execution of link, the you need to provide more details.
Update
According to your comments and edits you seem to need some one time initialization, as soon as the values are there. I suggest the following:
var init = scope.$watch('values', function(newVal, oldVal) {
if (newVal ==== oldVal) { //Use this if values is replaced, otherwise use a comparison of your choice
getInitValues();
init();
}
});
init() removes the watcher.
Related
I'm working on customize a input directive which including a label. I tried several days and refer to some articles.
The only problem is that except ng-change, ng-blur and ng-focus, all the other event work. https://jsfiddle.net/luneyq/mw3oz2pr/
Of course I can bind these three event manually myself and they can work as https://jsfiddle.net/luneyq/bp7f3z1o/
But I really don't know why ng-change, ng-blur and ng-focus don't work. Is there any special on these three event?
Anyone can help on this?
My codes are as below:
<div ng-app="myApp">
<div ng-controller="MainController">
<my-input type="number" name="valueNumber1" ng-model="obj.valueNumber1" label="Age" ng-click="log('click')" ng-change="log('change')" ng-blur="log('blur')" ng-focus="log('focus')" ng-mouseleave="log('mouseleave')"></my-input>
<div id="result"></div>
</div>
The JS:
var app = angular.module("myApp", []);
app.controller('MainController', function($scope, $window){
$scope.obj = {valueNumber1: 10};
$scope.log = function(text) {
document.getElementById("result").innerHTML = text + ':' + $scope.obj.valueNumber1 + "<br>" + document.getElementById("result").innerHTML;
};
});
app.directive('myInput', function() {
return {
require: '^ngModel',
restrict: 'EA',
scope: {
ngModel: '=',
name: '#name',
label: '#label'
},
replace: true,
transclude: true,
priority: 10,
template: '<div>' +
'<label for="{{ name }}">{{label}}</label>' +
'<input id="{{ name }}" ng-model="ngModel" />' +
'</div>',
compile: function(tElement, tAttrs, transclude) {
var tInput = tElement.find('input');
// Move the attributed given to 'custom-input' to the real input field
angular.forEach(tAttrs, function(value, key) {
if (key.charAt(0) == '$')
return;
tInput.attr(key, value);
});
tElement.replaceWith('<div class="cbay-input-div">' + tElement.html() + '</div>');
return;
}
};
});
Thanks in advance.
The issue is that compilation/transclusion/replace don't work the way you think they work (not sure where you made an incorrect assumption).
What is wrong with your code:
1). You are using incorrect attribute name: you should use tInput.attr(tAttrs.$attr[key], value); instead of tInput.attr(key, value);.
2). All the directives specified at my-input are compiled and linked despite your changes to the tElement in compile function. Proof is here - https://jsfiddle.net/fyuz3auc/3/, take a look at the myTest directive and its output in console: it is still applied to the myInput despite any of your effort.
3). You specified scope for your directive. Thus it has an isolated scope, thus anything you've compiled inside it has no access to log function of MainController, that's why your logs aren't working. Here is the fiddle proving that: https://jsfiddle.net/m5tba2mf/1/ (take a look at $scope.log = $scope.$parent.log in link function returned from compile).
In order to solve the second issue I suggest you to try alternative approach - I am using this at my project, and like it very much. The idea is to use terminal in conjunction with extremely high priority and $compile. Here is the updated fiddle, I think it is pretty straightforward what I do there: https://jsfiddle.net/uoat55sj/1/.
All:
Suppose I have two directives( dir1 and dir2) , which are both isolated scope. From some posts, I learnt that I need to use "require" to get scope of the other directive, but there is one question confused me so much:
Suppose I use ng-repeat generated a lot of dir1 and dir2, how do I know in certain dir1, which specific dir2's controller scope is required( cos there are many dir2 and in my understanding, all those scopes in dir2 controller are independent to each other)?
For example:
app.directive("dir1", function(){
var counter = 0;
return {
restrict:"AE",
scope:{},
template: "<button class='dir1_btn'>highlight dir2_"+(couter++)+" </button>",
link:function(scope, EL, attrs){
EL.find("button.dir1_btn").on("click", function(){
// How to let according dir2 know this click?
})
}
}
})
app.directive("dir2", function(){
var counter = 0;
return {
restrict:"AE",
scope:{},
template: "<span class='dir2_area'>This is dir2_"+(couter++)+" </span>",
link:function(scope, EL, attrs){
// Maybe put something here to listening the event passed from dir1?
}
}
})
And the html like( for simple purpose, I just put 2 of each there, actually it will generated by ng-repeat) :
<dir1></dir1>
<dir2></dir2>
<dir1></dir1>
<dir2></dir2>
Consider this just like the switch and light, dir1 is the switch to open(by change background-color) according light (dir2).
In actual project, what I want to do is angularJS directive version
sidemenu and scrollContent, each item in sidemenu is a directive,
click it will make according content(another directive) to auto scroll
to top.
I wonder how to do this? I know this is easy in jQuery, just wondering how to hook this into AngularJS data-driven pattern.
Thanks
The most important thing to note here is that I think you want to use ng-class Since you are creating both directives in an ng-repeat, I assume you are iterating over a list of objects (even if they are two separate ng-repeats, if you iterate over the same list of objects in both it will work. JQuery should not be necessary)? Attach an ngClass object to each object you iterate over, put it on an ng-class attribute in your dir2, then give dir1 access to change it. ngClass provides animation hooks if you want to animate the transition. The rest of my answer may help, though I would like to redo it now that I thought of ng-class. I have to get back to work for now though. I'll watch for feedback and try to answer quickly if you have questions.
I think there are probably a few ways to better accomplish what you are trying to do. It is not clear why both of your directives need to have isolate scopes. As I use angular more I find that though isolating a scope is a powerful technique, it is best to avoid over using it.
As for the require directive property, this post explains how to make directives communicate via their controllers very well.
I have two possible suggestions for you.
Make it one directive
Why can't you just put the templates into one?
Or if as I assume there is some reason they need to be separate, you could consider just sharing an object between them.
<div ng-repeat='obj in sharedDirObjs'>
<dir1 shared-dir-obj='obj'></dir1>
<dir2 shared-dir-obj='obj'></dir2>
</div>
app.controller('ctrl', function() {
$scope.sharedDirObjs = [obj1, obj2, obj3]
});
app.directive("dir1", function(){
var counter = 0;
return {
restrict:"AE",
scope:{sharedDirObj : '='},
template: "<button class='dir1_btn' ng-click='clickFn()'>highlight dir2_"+(couter++)+" </button>",
link:function(scope, EL, attrs){
var dir1vars...
scope.clickFn = function(){
// dir1 logic...
scope.sharedDirObj.dir2.clickFn(dir1vars...);
};
}
}})
app.directive("dir2", function(){
var counter = 0;
return {
restrict:"AE",
scope:{sharedDirObj : '='},
template: "<span class='dir2_area'>This is dir2_"+(couter++)+" </span>",
link:function(scope, EL, attrs){
scope.sharedDirObj.dir2 = {};
scope.sharedDirObj.dir2.clickFn(dir1vars...) {
// access to dir2 vars
};
}
}})
Similarly, you could create a service that holds an array of objects that are shared by injecting the service and indexed using the $index from the ng-repeat, or you could use an id system as PSL suggests. Note that the solution I describe above could work with isolate scope, or without it using scope.$eval(attr.sharedObj); on either or both of your directives. The answer to this question provides a solid runthrough of when and why to use isolated scope. In any case it would likely be best not to pipe functions through a shared object as I am showing above, and timing issues would need to be dealt with. Better would be to store properties on the object and set a scope.$watch on them in your dir2.
You may have to use some sort of strategy. Some kind of identifier hook up. Clearly you cannot use require(to require the controller of a directive and you don't have any also it can only look up to ancestors or itself not siblings). For example you could add an id attribute and a for attribute and target the element with a selection based on specific attribute value and fire an event. With this position of related element does not matter.
Your directive could look like:
<dir1 dir-for="id1"></dir1>
<dir2 dir-id="id1"></dir2>
<dir1 dir-for="id2"></dir1>
<dir2 dir-id="id2"></dir2>
and simple implementation:
.directive("dir1", function($document) {
var counter = 0;
return {
restrict: "AE",
scope: {
dirFor: '#'
},
template: "<button class='dir1_btn' ng-click='handleClick()'>highlight dir2_({{dirFor}}) </button>",
link: function(scope, EL, attrs) {
var $target = angular.element(
$document[0].querySelector('[dir-id="' + scope.dirFor + '"]'))
.contents().scope();
var clicked = false;
scope.handleClick = function() {
clicked = !clicked;
targetScope.$broadcast("SWITCH_CLICKED", clicked);
}
scope.$on('$destory',function() {
$target = null;
}
}
}
})
app.directive("dir2", function() {
var counter = 0;
return {
restrict: "AE",
scope: {
dirId: '#'
},
template: "<span class='dir2_area' ng-class=\"{true:'on', false:'off'}[status]\">This is dir2_{{dirId}}</span>",
link: function(scope, EL, attrs) {
console.log(scope.$id);
scope.status = false;
scope.$on('SWITCH_CLICKED', function(e, data) {
scope.status = data;
});
}
}
});
Demo
var app = angular.module('app', []).controller('ctrl', angular.noop);
app.directive("dir1", function($document) {
var counter = 0;
return {
restrict: "AE",
scope: {
dirFor: '#'
},
template: "<button class='dir1_btn' ng-click='handleClick()'>highlight dir2_({{dirFor}}) </button>",
link: function(scope, EL, attrs) {
var $target = angular.element($document[0].querySelector('[dir-id="' + scope.dirFor + '"]')).contents();
var clicked = false;
scope.handleClick = function() {
clicked = !clicked;
$target.scope().$broadcast("SWITCH_CLICKED", clicked);
}
scope.$on('$destroy',function() {
$target = null;
});
}
}
})
app.directive("dir2", function() {
var counter = 0;
return {
restrict: "AE",
scope: {
dirId: '#'
},
template: "<span class='dir2_area' ng-class=\"{true:'on', false:'off'}[status]\">This is dir2_{{dirId}}</span>",
link: function(scope, EL, attrs) {
scope.status = false;
scope.$on('SWITCH_CLICKED', function(e, data) {
scope.status = data;
});
}
}
})
.on{
color:green;
}
.off{
color:blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<dir1 dir-for="id1"></dir1>
<dir2 dir-id="id1"></dir2>
<dir1 dir-for="id2"></dir1>
<dir2 dir-id="id2"></dir2>
</div>
I have used $document[0].querySelector('[dir-id="' + scope.dirFor + '"]')).contents().scope() to get hold of the scope, similarly you could do .controller to get hold of the controller instance as well. Current example is doing an absolute selection(with document), you could as well make it relative.
I'm trying very hard to understand scopes in AngularJS and am running into problems.
I've created a simple "comments" application that
has an input box for publishing a comment (text + 'Reply' button) [this is working fine]
clicking 'Reply' button unhides another input box for publishing a reply (with a 'PublishReply' button)
clicking 'PublishReply' button, publishes the reply below the original comment and also indents it.
I generate comments within 'commentsDirective' using ng-repeat and embed a 'replyDirective' within each ng-repeat. I'm able to bind the parent scope's functions from the child directive's isolated scope, but I'm just not able to pass the arguments to this function.
Again, I think, a scope related problem is preventing me to hide/unhide the 'replyDirective' from the on-click of 'Reply' button.
Grateful for your help.
Here is the code in plunker: http://plnkr.co/edit/5AmlbOh6iEPby9K2LJDE?p=preview
<body ng-app="comments">
<div ng-controller="mainController">
<div class="publishComment"><input type="text" ng-model="contentForPublishing"/><button ng-click="publishComment(null, 0, contentForPublishing)">Publish Comment</button></div>
<comments-directive></comments-directive>
</div>
</body>
<script>
angular.module('comments', [])
.controller('mainController', function($scope) {
$scope.comments = [
{ id: 1, parentId: 0, content:'first comment'},
{ id: 2, parentId: 0, content:'second comment'}
];
$scope.publishComment = function (commentId, commentParentId, contentForPublishing){
if (commentId === null) {commentId = $scope.comments.length + 1;} // this (commentId === null) is sent only from the publishComments and not from publishReply
$scope.comments.push( { id: commentId, parentId:commentParentId, content:contentForPublishing } );
$scope.contentForPublishing = "";
}
$scope.replyWidgetVisible = false;
$scope.showReplyWidget = function() {
$scope.replyWidgetVisible = true;
}
})
.directive('commentsDirective', function() {
return {
restrict: 'E',
// template: '<div id="{{comment.id}}" class="commentWrapper" ng-class="{{ {true: '', false: 'indentLeft'}[{{comment.parentId}} === 0] }}" ng-repeat="comment in comments">' +
template: '<div id="{{comment.id}}" class="commentWrapper" ng-repeat="comment in comments">' +
'id: {{comment.id}} parentId: {{comment.parentId}}<br>>> {{comment.content}}<br>' +
'<button class="reply" ng-click="showReplyWidget()">Reply</button>' +
// '<reply-directive publish-reply="publishComment()" ng-show="{{replyWidgetVisible}}" reply-widget-visible="replyWidgetVisible"></reply-directive>' +
'<reply-directive publish-reply="publishComment()" comments-array="comments"></reply-directive>' +
'</div>'
};
})
.directive('replyDirective', function() {
return {
restrict: 'E',
scope: {
publishReply: '&',
commentsArray: '=',
replyWidgetVisible: '='
},
template: '<div class="publishComment"><input type="text" ng-model="contentForPublishing"/><button ng-click="publishReply(5, 1, contentForPublishing)">Publish Reply</button></div>'
};
});
</script>
Basically you need to "fetch" the publishComment function, since with publish-reply="publishComment()" you are telling Angular to call publishComment without any arguments, regardless of the arguments you are passing on your isolated scope. So, to actually reach the publishComment function (and not only the predefined executing function), so you can pass in arguments, you need to:
.directive('commentsDirective', function() {
return {
restrict: 'E',
template: '<div id="{{comment.id}}" class="commentWrapper" ng-repeat="comment in comments">' +
'id: {{comment.id}} parentId: {{comment.parentId}}<br>>> {{comment.content}}<br>' +
'<button class="reply" ng-click="showReplyWidget()">Reply</button>' +
'<reply-directive publish-reply="publishReply()" comments-array="comments"></reply-directive>' +
'</div>',
link: function(scope){
scope.publishReply = function(){
return scope.publishComment;
}
}
};
})
.directive('replyDirective', function() {
return {
restrict: 'E',
scope: {
publishReply: '&',
commentsArray: '=',
replyWidgetVisible: '='
},
template: '<div class="publishComment"><input type="text" ng-model="contentForPublishing"/><button ng-click="publishReply(5, 1, contentForPublishing)">Publish Reply</button></div>',
link: function(scope) {
scope.publishReply = scope.publishReply();
}
};
});
Think it like if you were doing: (function(){ return scope.publishComment(); })(5, 1, contentForPublishing);
Doing a "get reference to function" parent scope binding is mainly useful when the passed function is mutable. for example, my-cool-function="doThis()" and on another part of your app my-cool-function="doThat()". they exist so you can reuse the same directive in many situations, which isn't the case here.
A much simpler way would to $emit a publish event from your isolated scope and catch it in your comments directive. Or create a scope with true so you can access, in your newly created child scope, the function directly from the parent.
See updated plnkr in here http://plnkr.co/edit/nOWwFJ35XRXaIoxNPlW4?p=preview
Here is the plnkr showing how to keep just one reply box opened (you can keep as many open if you wish) http://plnkr.co/edit/za16eHPzltGLjK5ra1Vb?p=preview (see the revision before it for a widget state for each comment)
I'm new to AngularJS.
Can someone explain me why the active class not toggle between tabs in this code: http://jsfiddle.net/eSe2y/1/?
angular.module('myApp', [])
.filter('split', function () {
return function (input, string) {
var temp = string.split('|');
for (var i in temp)
input.push(temp[i]);
return input;
};
})
.directive('myTabs', function () {
return {
restrict: 'E',
scope: { tabs: '#' },
template:
"<div>" +
"<a ng-repeat='e in [] | split:tabs' ng-click='selectedIndex = $index' ng-class='{active:$index==selectedIndex}'>{{e}}</a>" +
"</div>",
replace: true
}
});
If I move the ng-click expression to a method of the controller, the code works as expected: http://jsfiddle.net/g36DY/1/.
angular.module('myApp', [])
.filter('split', function () {
return function (input, string) {
var temp = string.split('|');
for (var i in temp)
input.push(temp[i]);
return input;
};
})
.directive('myTabs', function () {
return {
restrict: 'E',
scope: { tabs: '#' },
template:
"<div>" +
"<a ng-repeat='e in [] | split:tabs' ng-click='onSelect($index)' ng-class='{active:$index==selectedIndex}'>{{e}}</a>" +
"</div>",
replace: true,
controller: ['$scope', function ($scope) {
$scope.onSelect = function (index) {
$scope.selectedIndex = index;
}
}]
}
});
Can someone explain me the difference? And how to modify the first code to make it works without create a method to the controller?
Thanks in advance.
Explanation of the Problem
The problem has to do with javascript inheritance as it relates to scopes and directives in angular. Basically, when in a child scope, all properties of basic types (int, boolean, etc) are copied from the parent.
In your case, the ng-repeat directive creates a child scope for each element, so each one of the links has its own scope. in the first example, selectedIndex is only referenced from within the repeater, each repeater element references its own copy of the selectedIndex. You can investigate this using the
In the second example, you define a selectedIndex object in the controller, which is the parent scope for the repeater. Because the selectedIndex property is undefined initially when it is passed into the controllers, they look to the parent for a definition. When this definition has a value set in the onSelect method, all of the repeater elements "see" this value, and update accordingly.
How to Debug
In the future, you can investigate these types issue using the Angular Batarang.
browse to http://jsfiddle.net/eSe2y/1/show
left-click one of the tabs
right-click the same link
select "inspect element"
open the debug console and type $scope.selectedIndex
repeat the above steps for another tab, and note how the value differs
now go to the elements tab of the debugger, and click on the div
enter $scope.selectedIndex and note that it is undefined
On the second fiddle, try viewing just the $scope on each of the tabs (not $scope.selectedIndex). You will see that selectedIndex is not defined on the repeater elements, so they default to the value from their parent.
Best Practices
The typical angular best practice to avoid this problem is to always reference items that could be change on the scope "after the dot". This takes advantage of the fact that JavaScript objects are inherited by reference, so when the property changes in one place, it changes for all scopes in the parent-child hierarchy. I've posted an updated fiddler that fixes the problem by simply pushing the binding onto an object:
angular.module('myApp', [])
.filter('split', function () {
return function (input, string) {
var temp = string.split('|');
for (var i in temp)
input.push(temp[i]);
return input;
};
})
.directive('myTabs', function () {
return {
restrict: 'E',
scope: { tabs: '#' },
template:
"<div>" +
"<a ng-repeat='e in [] | split:tabs' ng-click='s.selectedIndex = $index' ng-class='{active:$index==s.selectedIndex}'>{{e}}</a>" +
"</div>",
replace: true,
controller: ['$scope', function ($scope) {
$scope.s = {};
}]
}
});
http://jsfiddle.net/g36DY/2/
Angular newbie here. I am trying to figure out what's going wrong while passing objects to directives.
here's my directive:
app.directive('walkmap', function() {
return {
restrict: 'A',
transclude: true,
scope: { walks: '=walkmap' },
template: '<div id="map_canvas"></div>',
link: function(scope, element, attrs)
{
console.log(scope);
console.log(scope.walks);
}
};
});
and this is the template where I call the directive:
<div walkmap="store.walks"></div>
store.walks is an array of objects.
When I run this, scope.walks logs as undefined while scope logs fine as an Scope and even has a walks child with all the data that I am looking for.
I am not sure what I am doing wrong here because this exact method has worked previously for me.
EDIT:
I've created a plunker with all the required code: http://plnkr.co/edit/uJCxrG
As you can see the {{walks}} is available in the scope but I need to access it in the link function where it is still logging as undefined.
Since you are using $resource to obtain your data, the directive's link function is running before the data is available (because the results from $resource are asynchronous), so the first time in the link function scope.walks will be empty/undefined. Since your directive template contains {{}}s, Angular sets up a $watch on walks, so when the $resource populates the data, the $watch triggers and the display updates. This also explains why you see the walks data in the console -- by the time you click the link to expand the scope, the data is populated.
To solve your issue, in your link function $watch to know when the data is available:
scope.$watch('walks', function(walks) {
console.log(scope.walks, walks);
})
In your production code, just guard against it being undefined:
scope.$watch('walks', function(walks) {
if(walks) { ... }
})
Update: If you are using a version of Angular where $resource supports promises, see also #sawe's answer.
you may also use
scope.walks.$promise.then(function(walks) {
if(walks) {
console.log(walks);
}
});
Another solution would be to add ControllerAs to the directive by which you can access the directive's variables.
app.directive('walkmap', function() {
return {
restrict: 'A',
transclude: true,
controllerAs: 'dir',
scope: { walks: '=walkmap' },
template: '<div id="map_canvas"></div>',
link: function(scope, element, attrs)
{
console.log(scope);
console.log(scope.walks);
}
};
});
And then, in your view, pass the variable using the controllerAs variable.
<div walkmap="store.walks" ng-init="dir.store.walks"></div>
Try:
<div walk-map="{{store.walks}}"></div>
angular.module('app').directive('walkMap', function($parse) {
return {
link: function(scope, el, attrs) {
console.log($parse(attrs.walkMap)(scope));
}
}
});
your declared $scope.store is not visible from the controller..you declare it inside a function..so it's only visible in the scope of that function, you need declare this outside:
app.controller('MainCtrl', function($scope, $resource, ClientData) {
$scope.store=[]; // <- declared in the "javascript" controller scope
ClientData.get({}, function(clientData) {
self.original = clientData;
$scope.clientData = new ClientData(self.original);
var storeToGet = "150-001 KT";
angular.forEach(clientData.stores, function(store){
if(store.name == storeToGet ) {
$scope.store = store; //declared here it's only visible inside the forEach
}
});
});
});