angular scoping issue across controllers, not automatically updating the view - javascript

So I'm having an issue with my ng-repeat in my displayCtrl. I'm able to add objects to my $scope.votes array on an ajax call as intended, but that's not being automatically updated in the view. Thoughts? Here's my script:
var glassCongress = angular.module('glassCongress', []).run(function($rootScope){
$rootScope.votes = [];
}).controller('searchCtrl', function($scope, $rootScope, $http){
$(document).ready(function() {
$('#sendstuff').on('submit',function(event) {
event.preventDefault();
$.ajax({
url: '/search/' + $('#input').val(),
type: 'GET',
dataType: 'json'
}).done(function(data){
for(var voteIndex = 0; voteIndex < data.data.length; voteIndex++){
$rootscope.votes.push({
"voteValue": (data.data[voteIndex].option.value)
})
}
})
})
})
}).controller('displayCtrl', function($scope, $rootScope){
})
And here's my html:
<html ng-app="glassCongress">
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.1/angular.min.js"> </script>
<script src="script.js"></script>
</head>
<body>
<div id="search" ng-controller = "searchCtrl">
<div>
<form id='sendstuff' action='senddata' method='get'>
<input id='input' type='text'/>
<input type="submit" value="Submit" />
</form>
</div>
</div>
<div id="display" ng-controller = "displayCtrl">
<div>
<ul>
<li ng-repeat="vote in votes"><span>{{vote}}</span></li>
</ul>
</div>
</div>
</body>
</html>
Thanks guys!

Your $.ajax call runs out of the angularjs scope. Becouse of that, anglarjs don't update the view automaticly.
There is tow possible solutions.
1 - use the $http module. You can replace the $.ajax call by $http call. Read the doc to get more information.
2 - after change your model in ajax callback, call the method $acope.apply() to force angularjs update your view.
Inset use $rootScope, you should use $scope.

Related

ng-repeat not iterating through list of images in JSON

I'm quite new to Angular and am having trouble using the $http service to make a GET request for images in JSON (just a plain array of images). For every image, I want to repeat that and add them into my ng-src. I'm trying to achieve a layout similar to Instagram.
So I think the $http.get part is correct where I store it into $scope.imageUrls, and from there I iterate through it using ng-repeat. Then from there, for each iteration, I plug that into ng-src in my img tag and I just don't know how to debug from there.
HTML:
<div class="posts" ng-controller="PostController">
<div class="post" ng-repeat="imageUrl in imageUrls">
<img class="photo" ng-src="{{imageUrl}}" />
<div class="post-box">
<div><span class="likes"> # </span> Likes</div>
</div>
</div>
</div>
JS:
var app = angular.module('instagram', []);
app.controller('PostController', ['$scope', '$http', function($scope, $http) {
$http.get('https://codesmith-precourse.firebaseio.com/instagram/-JqL35o8u6t3dTQaFXSV.json')
.then(function (data) {
$scope.imageUrls = data;
console.log($scope.imageUrls);
});
}]);
I tried used console.log to check for errors, but the data seems to be there. Is it just returning the block of data rather than each element/image in the JSON?
Checking the console: console.log($scope.imageUrls)
I also tried using {{imageUrl.url}} as ng-src but that seemed to trigger errors as well. I set up a Plnkr:
http://plnkr.co/edit/yQpCIRp9FHdDHTMA1HCL?p=preview
This has been bugging me for awhile, so if you can help, thanks!
I update your plunker http://plnkr.co/edit/hNn1YdVh8w7l3dEgh3LU?p=preview:
In $http you get a responsa that contains more informations that only data. To get data you must do it :
$http.get('https://codesmith-precourse.firebaseio.com/instagram/-JqL35o8u6t3dTQaFXSV.json')
.then(function (response) {
$scope.imageUrls = response.data;
console.log($scope.imageUrls);
});
And in ng-repeat you must add track by argument because image can be duplicate
You are setting imageUrls to an object. It needs to be an array. If you look in the debugger your response is this:
You want whats in data.data (You also should define the imageUrls variable ($scope.imageUrls = []')
<!doctype html>
<html ng-app="instagram">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Angular</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="posts" ng-controller="PostController">
<div class="post" ng-repeat="imageUrl in imageUrls">
<img class="photo" ng-src="{{imageUrl}}" />
<div class="post-box">
<div><span class="likes"> # </span> Likes</div>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-2.2.4.js" integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI=" crossorigin="anonymous"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script>
var app = angular.module('instagram', []);
app.controller('PostController', ['$scope', '$http', function($scope, $http) {
$scope.imageUrls = [];
$http.get('https://codesmith-precourse.firebaseio.com/instagram/-JqL35o8u6t3dTQaFXSV.json')
.then(function (data) {
$scope.imageUrls = data.data;
});
}]);
</script>
</body>
</html>
updated plunkr http://plnkr.co/edit/agVrWD8I4581a0702ehy?p=preview
you have to get data.data
$http.get('https://codesmith-precourse.firebaseio.com/instagram/-JqL35o8u6t3dTQaFXSV.json')
.then(function (data) {
$scope.imageUrls = data.data;
});
and use track by $index in the ng-repeat because you have duplicate
<div class="posts" ng-controller="PostController">
<div class="post" ng-repeat="imageUrl in imageUrls track by $index">
<img class="photo" ng-src="{{imageUrl}}" />
<div class="post-box">
<div><span class="likes"> # </span> Likes</div>
</div>
</div>
</div>
First of all in $http method the response value is an object containing "data" element that is the data you need so use this :
$scope.imageUrls = data.data;
then you have duplicate image url , in this case ng-repeat returns an error so use this instead :
<div class="post" ng-repeat="imageUrl in imageUrls track by $index">

Beginners help to Angular JS debugging via console errors

AngularJS is new to me (and difficult). So I would like to learn how to debug.
Currently I'm following a course and messed something up. Would like to know how to interpret the console error and solve the bug.
plnkr.co code
index.html
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="MainController">
<h1>{{message}}</h1>
{{ username }}
<form action="searchUser" ng-submit="search(username)">
<input type="search"
required placeholder="Username to find"
ng-model="username"/>
<input type="submit" value="search">
</form>
<div>
<p>Username found: {{user.name + error}}</p>
<img ng-src="http://www.gravatar.com/avatar/{{user.gravatar_id}}" title="{{user.name}}"/>
</div>
</body>
</html>
script.js
(function() {
var app = angular.module("githubViewer", []);
var MainController = function($scope, $http) {
var onUserComplete = function(response) {
$scope.user = response.data;
};
var onError = function(reason) {
$scope.error = "could not fetch data";
};
$scope.search = function(username) {
$http.get("https://api.github.com/users/" + username)
.then(onUserComplete, onError);
};
$scope.username = "angular";
$scope.message = "GitHub Viewer"; };
app.controller("MainController", MainController);
}());
The console only says
searchUser:1 GET http://run.plnkr.co/lZX5It1qGRq2JGHL/searchUser? 404
(Not Found)
Any help would be appreciated.
In your form, action you have written this
<form action="searchUser"
What this does is it will try to submit to a url with currentHostName\searchUser, so in this case your are testing on plunker hence the plunker url.
You can change the url where the form is submitted. Incase you want to search ajax wise then you dont even need to specify the action part. You can let your service/factory make that call for you.
Though not exactly related to debugging this particular error, there is a chrome extension "ng-inspector" which is very useful for angularJS newbies. You can view the value each of your angular variable scopewise and their value. Hope it helps!
Here is the link of the chrome extension: https://chrome.google.com/webstore/detail/ng-inspector-for-angularj/aadgmnobpdmgmigaicncghmmoeflnamj?hl=en
Since you are using ng-submit page is being redirected before the response arrives and you provided any action URL as searchUser which is not a state or any html file so it being used to unknown address, it is async call so it will take some time you can use input types as button instead of submit.
Here is the working plunker.
<!DOCTYPE html>
<html ng-app="githubViewer">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="MainController">
<h1>{{message}}</h1>
{{ username }}
<form >
<input type="search"
required placeholder="Username to find"
ng-model="username"/>
<input type="button" ng-click="search(username)" value="search">
</form>
<div>
<p>Username found: {{user.name + error}} {{user}}</p>
<img ng-src="http://www.gravatar.com/avatar/{{user.gravatar_id}}" title="{{user.name}}"/>
</div>
</body>
</html>

angular.js ui-router pass no data

In my Ionic app, I want to pass parameter(s) from one sub-view to another sub-view. When I pass parameters first time, It works as I expected, but my problem is, when I return first sub-view and then go to another sub-view, it goes to that page without parameters. My code is given below:
index.html (project/www)
<!DOCTYPE html>
<html>
<head>
<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<script src="lib/ionic/js/ionic.bundle.js"></script>
<script src="lib/ngCordova/dist/ng-cordova.js"></script>
<script src="cordova.js"></script>
<script src="js/app.js"></script>
<script src="js/main.js"></script>
<script src="js/routes.js"></script>
</head>
<body ng-app="app" animation="slide-left-right-ios7" >
<!-- main window -->
<div>
<ion-nav-view></ion-nav-view>
</div>
</body>
</html>
route.js (www/js/route.js)
angular.module('app.routes', [])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('mainUser', { // first window
url: '/mainuser',
templateUrl: 'templates/mainUser.html',
controller: 'mainCtrl'
})
.state('userDrive', { // second window
url: '/user_drive',
params: {
driveData: null // parameter send
},
templateUrl: 'templates/user_drive.html',
controller: 'DriveCtrl'
});
$urlRouterProvider.otherwise('/mainUser');
});
templates/mainUser.html
<ion-side-menus>
<ion-side-menu-content>
<ion-content class="padding" style="background-color:#fff;">
<input type="date" ng-model="selectData.selectedDate" placeholder="Date">
<input type="time" ng-model="selectData.selectedTime" placeholder="Time">
</ion-content>
<div class="bar bar-footer">
<div class="button-bar">
<a ui-sref="userDrive({ driveData: selectData })" class="button"> Drive </a>
</div>
</div>
</ion-side-menu-content>
</ion-side-menus>
Here after click on Drive button, it will redirect to userDrive sub-view with parameter driveData correctly. But where I back to mainUser and then change selectData.selectedDate and selectData.selectedTime and then click again on Drive button, it will redirect to userDrive sub-view without driveData parameter.
userDrive Controller
.controller('DriveCtrl', function($scope, $state, $stateParams) {
console.log("DriveCtrl"); // after redirect to this controller second time
// it also print no value
// seems might be DriveCtrl is not called
console.log("$stateParams : ", $stateParams);
})
The problem is that the view is cached by Ionic, and in that case the controller gets executed only once, so that's why you only see the log the first time.
You need to use ionic view events, here the docs: http://ionicframework.com/docs/api/directive/ionView/
#leandro-zubrezki is right. To remove cache you can add anywhere in the controller 'DriveCtrl'.
$scope.$on("$ionicView.afterLeave", function () {
$ionicHistory.clearCache();
});
U can't send object into state param, if u need to send each value separately

Calling an AngularJS controller function from outside of it

I have the following code:
app.controller('MatrixExpertCtrl', function($scope,$http){
$scope.PassedMatrix=[];
$scope.GetMatrixFromServer=function(){
$http.get("http://localhost:3000/getmatrixfromdb").success(function(resp){
alert("The matrix grabbed from the server is: " + resp[0].ans);
$scope.PassedMatrix.push(resp[0].ans);
});
};
$scope.DispSize=function(){
alert("testing");
alert("The size is "+$scope.PassedMatrix[0].size) ;
};
//$scope.GetMatrixFromServer();
});
Now, suppose, in HTML, I have something like this:
<div class="col-sm-3 col-md-3 col-lg-3">
<div class="text-center">
<h3>Example Survey</h3>
<p>example paragrah</p>
<p>More random text</p>
<p>ending the paragraphs</p>
<button id="updmat" ng-click="DispSize();" type="button" class="btn btn-default">Updates</button>
</div>
//Much more code
<div id="body2">
<div class="col-sm-6 col-md-6 col-lg-6" style="background-color:#ecf0f1;">
<div ng-controller="MatrixExpertCtrl" ng-app="app" data-ng-init="GetMatrixFromServer()">
<div class="text-center">
Meaning with this:
Is it possible to call a function that is defined inside a controller, from outside of the scope of that same controller?
I need this because the function is manipulating a shared object, owned by the controller in a very very simple fashion (for example, clicking on the button changes the color of a given element).
I am having trouble to make this work, any help will be appreciated.
I think that declaring some data structures as global would help me solving this problem, but, I would like to avoid doing that because, besides it being bad practice, it might bring me more problems in the future.
If i understand your problem correctly than what you basically do have is one utility function which will work on your shared object and do your useful things (i.e. clicking on the button changes the color of a given element) and now you do require the same behaviour in another controller outside of it's scope. You can achieve the same thing in 2 different ways :
1).Create a service and make it available in your controllers like this :
<!doctype html>
<html ng-app="myApp">
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.angularjs.org/1.1.2/angular.min.js"></script>
<script type="text/javascript">
var myApp = angular.module('myApp', []);
myApp.factory('myService', function() {
return {
changeColour: function() {
alert("Changing the colour to green!");
}
};
});
myApp.controller('MainCtrl', ['$scope', 'myService', function($scope,
myService) {
$scope.callChangeColour = function() {
myService.changeColour();
}
}]);
</script>
</head>
<body ng-controller="MainCtrl">
<button ng-click="callChangeColour()">Call ChangeColour</button>
</body>
</html>
Pros&Cons: More angularistic way, but overhead to add dependency in every different controllers and adding methods accordingly.
2).Access it via rootscope
<!doctype html>
<html ng-app="myApp">
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.angularjs.org/1.1.2/angular.min.js"></script>
<script type="text/javascript">
var myApp = angular.module('myApp', []);
myApp.run(function($rootScope) {
$rootScope.globalChangeColour = function() {
alert("Changing the colour to green!");
};
});
myApp.controller('MainCtrl', ['$scope', function($scope){
}]);
</script>
</head>
<body ng-controller="MainCtrl">
<button ng-click="globalChangeColour()">Call global changing colour</button>
</body>
</html>
Pros&Cons: In this way, all of your templates can call your method without having to pass it to the template from the controller. polluting Root scope if there are lots of such methods.
try removing semicolon
ng-click="DispSize()"
because it binds ng-click directive to the function.

ajax call on angularjs

I am trying to validate a number input using angularjs.
The page works as desired by itself, however it does not work when I call the page with ajax.
Any help or advice would be appreciated!
Working angularjs jlgtest3.jsp ...
<div ng-app="total">
<script>
angular.module('total', [])
.controller('totalController', ['$scope', function($scope) { }]);
</script>
<form name="totalForm" ng-controller="totalController">
<input name="totalHours" ng-model="total" type="number" value="" />
<p ng-show="totalForm.totalHours.$error.number">Not valid number!</p>
</form>
</div>
</html>
Not working with ajax call (jlgtest4.jsp calling jlgtest3.jsp)...
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script>
function newajax() {
var xRequest1;
if(window.XMLHttpRequest)
{
xRequest1=new XMLHttpRequest();
} else {
xRequest1=new ActiveXObject("Microsoft.XMLHTTP");
}
xRequest1.onreadystatechange=function ()
{
if((xRequest1.readyState==4) && (xRequest1.status==200))
{
document.getElementById("test").innerHTML=xRequest1.responseText;
}
}
var urlencode = "jlgtest3.jsp";
xRequest1.open("post",urlencode,true);
xRequest1.send();
}
</script>
</head>
<input type="button" onclick="newajax()" value="button" />
<div id="test">
</div>
</html>
I attempted the angular ajax call as some people suggested, but I couldnt get it to work...
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<div ng-app="total">
<script>
angular.module('total', [])
.controller('totalController', ['$scope', function($scope) {
$http.POST("jlgtest3.jsp").then(function(response) {
$scope.test = response.data;
});
}]);
</script>
<div ng-controller="totalController">
<input type="button" value="button" />
{{test}}
</div>
</div>
</html>
If you're using Angular, you should consider using the $http service or even the $resource service. These both abstract ajax requests into a much simpler form. So instead of
xRequest1.open("post",urlencode,true);
xRequest1.send();
...etc...
You might have something like:
$http.POST(urlencode).then(function(response) {
document.getElementById("test").innerHTML=response.data;
// do other stuff with the response
});
And that will encapsulate essentially your entire newajax function.
As for #messerbill 's answer, you should not be making $http calls in your controller. These are better utilized within a service or factory that you then inject into your controller. Controllers are for business logic and should not deal with fetching and sending data.
you also can use a standart Ajax call but better use the $http angular way. You should call it inside of your angular controller.
XMLHttpRequest is an object used by Ajax - https://en.wikipedia.org/wiki/XMLHttpRequest
https://docs.angularjs.org/api/ng/service/$http
updated answer
Why dont you use Angular in the way its meant to be used? You should send your post inside of you angular service or controller. Don't manipulate your DOM if you use AngularJS like you did here:
document.getElementById("test").innerHTML=response.data;
istead you should do it that way:
angular.module('total', [])
.controller('totalController', ['$scope', function($scope) {
$http.POST("yourURL").then(function(response) {
$scope.test = response.data;
});
}]);
//template
<input type="button" value="button" />
<div ng-controller="totalController">
{{test}}
</div>
</html>
I have not tested it yet, but it should work - next time create a fiddle ;)
I posted this question again, but a little bit more simplified and Moncef Hassein-bey was able to answer my question Use Ajax to put external angularjs element in html page
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script>
angular.module('myApp', [])
.controller('myController', ['$scope', function($scope) { }]);
</script>
<script>
function newajax() {
var xRequest1;
xRequest1=new XMLHttpRequest();
xRequest1.onreadystatechange=function ()
{
if((xRequest1.readyState==4) && (xRequest1.status==200))
{
document.getElementById("test").innerHTML=xRequest1.responseText;
angular.bootstrap(document.getElementById('test'), ['myApp']);
}
}
xRequest1.open("post","jlgtest.html",true);
xRequest1.send();
}
</script>
<input type="button" value="button" onClick="newajax()" />
<div id="test">
</div>
</div>
</html>
Basically I needed to add the angular.bootstrap line of code, and the angular.module(... script needed to be in my main page
this is the called page code...
<html>
<div ng-app="myApp">
<form name="myForm" ng-controller="myController">
<input name="numberField" ng-model="myModel" type="number" value="" />
<p ng-show="myForm.numberField.$error.number">Not valid number!</p>
</form>
</div>
</html>

Categories