angular scope variable has no data - angularjs

I'm pretty new to angular js but it seems like my simple code should work. Here is the html:
<body ng-app="MyHomepage">
<div ng-controller="RedditLoad">
{{a}}
<ul>
<li ng-repeat="article in a">
{{article.data.title}}
</li....
and here is my angualr_app.js:
var App = angular.module('MyHomepage', [])
function RedditLoad($scope){
$.getJSON("http://www.reddit.com/.json?jsonp=?", function(data) {
var data_array = [];
$.each(data.data.children, function(i,item){
data_array.push(item);
});
console.log(data_array);
$scope.a = data_array;
});
}
What am I doing wrong? console.log(data_array); is showing the correct values but the data wont seem to get passed to the template.

The getJSON callback isn't executed in the angular context so angular doesn't know about your changes and won't refresh the bindings. When code is called from an external source (like a jQuery event ), you have to encapsulate your scope changes in an $apply call:
$scope.$apply(function{
$scope.a = data_array;
}

Related

Angular $scope not getting variables

I have a simple html file that make make search on Algolia and returns result. I can console the result but can not access $scope.users from view. How can I grab that $scope.users in view.
here is my app.js file
var myApp = angular.module('myApp', []);
myApp.controller('usersController', function($scope) {
$scope.users = [];
var client = algoliasearch('my_app_id', 'my_app_key');
var index = client.initIndex('getstarted_actors');
index.search('john', function searchDone(err, content) {
$scope.users.push(content.hits);
console.log(content.hits);
});
});
Here is my html view file
<div class="results" ng-controller="usersController">
<div ng-repeat="user in users">
<h3>{{ user.name }}</h3>
</div>
</div>
note: ng-app="myApp" attribute given in html tag.
It's most likely because your index.search call isn't triggering an Angular $digest cycle - manually trigger one with either $apply or a $timeout
index.search('john', function searchDone(err, content) {
$scope.users.push(content.hits);
$scope.$apply();
});
The $apply() could throw $digest already in progress errors - another way with a $timeout
myApp.controller('usersController', function($scope, $timeout) {
index.search('john', function searchDone(err, content) {
$timeout(function() {
$scope.users.push(content.hits);
});
});
});
try calling $scope.$apply() to update your bindings
index.search('john', function searchDone(err, content) {
$scope.users.push(content.hits);
console.log(content.hits);
$scope.$apply();
});
algoliasearch doesn't look like it's an injected service and therefore not native to the angular framework. Try calling $scope.$apply().

Pass value to Angular controller through ng-include

From a server side code I am loading and angular template as follows:
<div ng-include="'/views/signup.html'" onload="init('premium')"></div>
The view is, for now, the following:
<form ng-controller="AccountSignupController as controller">
</form>
The controller is simply:
function AccountSignupController($scope) {
$scope.plan = '';
$scope.init = function (plan) {
$scope.plan = plan;
console.log(plan);
};
};
On the console plan is always "undefined".
How can I pass a value to the controller through the template?
Do I need to set the controller on ng-include div and use ng-init?
The scope of the controller is inside the form where 'ng-controller' is. Thus $scope.init function is only "available" inside that form.
Both directives should be at the same level. Try moving 'ng-controller' to the div or 'ng-init' to the form (if possible).
You are instantiating your controller using the controller as binding syntax. In that case properties and functions are bound to the this of your controller instead of $scope. Functions should be called using the binding.
Your template should be:
<div ng-include="'/views/signup.html'"
ng-controller="AccountSignupController as controller"
onload="controller.init('premium')"></div>
Your controller:
function AccountSignupController() {
var self = this;
this.plan = '';
this.init = function (initString) {
self.plan = initString;
console.log(initString);
};
};
For more information on the controller as binding syntax, see the AngularJS ngController API

AngularJs Inline Check if an array check

Inline in AngularJs is there a way to check if something is an array?
I would have thought this to work:
<div ng-show="Array.isArray(textStuff[0][1])">Hi</div>
I have verified it is in fact an array. Is there something I am missing or another way?
You can put angular.isArray on the scope...
$scope.isArray = angular.isArray;
<div ng-show="isArray(textStuff[0][1])">Hi</div>
Fiddle
You can create global filters to use in your JS or HTML to check against object types. This way you don't pollute your $rootScope or $scopes to use it everywhere, unlike the accepted answer... Angular also has some built in utility functions that can check object types:
angular
.module("yourModule")
.filter("isArray", function() {
return function(input) {
return angular.isArray(input);
};
});
In HTML:
<div ng-show="{{ textStuff[0][1]) | isArray }}">Hi</div>
You may also inject the $filter service into your Controller to access the custom filter by name and compute the filtered results when your controller instance is instantiated (and also when your data changes). This prevents performance issues due to the view expression getting computed rapidly.
angular
.module("yourModule")
.controller("MyController", MyController);
MyController.$inject = ["$filter", "$scope"];
function MyController($filter, $scope) {
this.testStuff = []; // your data
this.filteredResult = $filter("isArray")(this.testStuff[0][1]);
// or if you need to watch for data changes
var vm = this;
$scope.$watchCollection(
function() { return vm.testStuff },
function(newTestStuff) {
vm.filteredResult = $filter("isArray")(newTestStuff[0][1]);
}
);
}
<div ng-controller="MyController as my">
<div ng-show="my.filterResult">Hi</div>
</div>
I would separate logic from the view. Add state in scope and then check it
$scope.showHi = angular.isArray(textStuff[0][1]);
In view
<div ng-show="showHi">Hi</div>

angular.js controller as syntax template binding using $template cache service

i have already used angular js before but now i am using controller as syntax in angular js and i am not able to bind template.
My controller code:
(function () {
angular.module("vkApp")
.controller("Feeds", Feeds);
function Feeds(FeedSetting, FeedLoader, $templateCache, $compile) {
var vm = this;
FeedSetting.initializeSetting(vm);
//functions declaration
vm.addFeed = addFeed;
// function implementations
function addFeed(text) {
return FeedLoader.loadFeed("http://rss.cnn.com/rss/edition_world.rss")
.then(function (feedData) {
console.log(feedData.data.responseData.feed);
vm.feedList = feedData.data.responseData.feed;
var feedTemplate = $templateCache.get("feedTemplate");
feedTemplate.then(function (markup) {
$compile(markup.data)(vm).appendTo(angular.element("#FeedArea"));
});
return vm.feedList;
});
}
};
})();
My template is:
<h7>{{feed.feedList.title}}</h7>
feed.html page:
<div id="rightSide" ng-controller="Feeds as feed">
<div class="news-feed-wrapper" id="FeedArea">
</div>
</div>
when the binding is performed it gives me error in console
You need to make couple of changes
1)Replace this line
$compile(markup.data)(vm).appendTo(angular.element("#FeedArea"));
with
$compile(markup.data)($scope).appendTo(angular.element("#FeedArea"));
because behind the scene your custom variable vm bind with Angular $scope. So $compile would work the same like it was using classic controller with $scope syntax
2) And in your binding replace
<h7>{{feed.feedList.title}}</h7>
with
<h7>{{vm.feedList.title}}</h7>
3) And inside Feed.html
ng-controller="Feeds as feed"
should be
ng-controller="Feeds as vm"
After the above changes it should work.

Dynamically add existing controller into another controller with AngularJS

in my app I have a wrapper controller that handles some properties dynamically based on other-controllers within it. everything works like a charm if the other-controllers are present/static on load, but as soon as I'm trying to make them dynamic, they stop working.
It was my understanding that the $rootScope is available from everywhere within the app, is that not true?
my JS looks like this:
var webApp = angular.module("webApp",[]);
webApp.controller("ControllerA", function($scope, $rootScope){
$rootScope.cnt = 0;
$rootScope.cntPlusPlus = function(){
$rootScope.cnt++;
};
$rootScope.controllerBs = [];
var template = $(".controller-b").html();
$scope.addControllerB = function(){
$rootScope.controllerBs.push(template);
};
});
webApp.controller("ControllerB", function($scope, $rootScope){
$scope.cntPlusPlus = function(){
console.log("overwrite plus plus");
}
});
Full example: http://plnkr.co/edit/tAcv1F9y7t9q9XsQ1EFL?p=preview
I know that this would be probably better with directives, but is there any way to make it work with Controllers?
thanks for the help
Don't try to access the DOM from controller code. Never. It is very bad practice which breaks AngularJS conventions and eventually provides you with bad architecture. This also means you should not create any DOM elements manually from a controller.
Better to manipulate with the scope itself, not with its visual representation. You can add new models to scope on your button's click, which will be translated to new elements by ng-repeat directive, each with its own controller (remember controllers are instances, not singletons, so that they have separated life cycles).
You might want to make use of <script type="text/ng-template"> and ng-include here instead of hidden divs.
Try to avoid using $rootScope when possible - it is global state which can be dangerous.
It might look like this then (plunker):
HTML:
<div class="controller-a" ng-controller="ControllerA">
Controller A
<div>
<button ng-click="cntPlusPlus()">cnt++</button> CNT: {{cnt}}
</div>
<button ng-click="addB()">Add B</button>
<div ng-repeat="B in Bs">
<div ng-include="'b-template'"></div>
</div>
</div>
<script type="text/ng-template" id="b-template">
<div ng-controller="ControllerB">this is controller b: <button ng-click="cntPlusPlus()">cnt++</button></div>
</script>
JS:
var webApp = angular.module("webApp",[]);
webApp.controller("ControllerA", function($scope){
$scope.cnt = 0;
$scope.cntPlusPlus = function(){
$scope.cnt++;
};
$scope.Bs = [];
$scope.addB = function(){
$scope.Bs.push({});
};
});
webApp.controller("ControllerB", function($scope){
$scope.cntPlusPlus = function(){
console.log("overwrite plus plus");
$scope.$parent.$parent.$parent.cnt++; //should be moved to service
}
});
</script>

Resources