AngularJS - Binding/Replacing AJAX content - javascript

I am using AngularJS to load AJAX content and using ng-repeat to create a list of items. On the content I also have {{noun}} as a placeholder. My assumption was that when the ajax content is loaded, AngularJS would automatically replace {{noun}} with the data from $scope.noun model. But it isn't the case. Any quick and dirty way to make it happen?
Here's my code:
AllControllers.controller('AppController', ['$scope', '$http', function ($scope, $http) {
$scope.noun = "My Noun";
$scope.headlines = [{
headline: "Top 10 Tricks to {{noun}}",
usage: 10,
votes: 100
}];
$scope.load_headlines = function() {
$http.get('/data/headlines.json').
success(function(data, status, headers, config){
$scope.headlines = data;
}).
error(function(data, status, headers, config){
console.log(status);
});
};
}]);
<div ng-controller="AppController" ng-init="load_headlines()">
<table>
<tbody ng-repeat="headline in headlines">
<tr>
<td>{{headline.headline}}</td>
<td class="center">{{headline.usage}}</td>
<td class="center">{{headline.votes}}</td>
</tr>
</tbody>
</table>
</div>

Your $scope variable is differently to the ngRepeat variable.
I think you have to change the $scope variable in your controller:
$scope.headlines_displayed = [{
headline: "Top 10 Tricks to "+$scope.noun,
usage: 10,
votes: 100
}];

you can binding the {{moon}} in the td repeated.
change the code like this:
AllControllers.controller('AppController', ['$scope', '$http', function ($scope, $http) {
$scope.noun = "My Noun";
$scope.headlines = [{
headline: "Top 10 Tricks to ",
usage: 10,
votes: 100
}];
}]);
<tbody ng-repeat="headline in headlines_displayed">
<tr>
<td>{{headline.headline}} {{noun}}</td>
<td class="center">{{headline.usage}}</td>
<td class="center">{{headline.votes}}</td>
</tr>
</tbody>

Figured it out. Ended up doing this:
<td>{{headline.headline.replace("{{noun\}\}", noun)}}</td>

You should be using $interpolate service to compile the string before assigning it to the scope. Passing a string with {{}} will not work. In your http success callback do something like this. This will replace your {{noun}} with scope value.
$scope.load_headlines = function() {
$http.get('/data/headlines.json').
success(function(data, status, headers, config){
$scope.headlines = data;
$interpolate($scope.headlines.headline)($scope);
}).
error(function(data, status, headers, config){
console.log(status);
});
};
}]);
Take a look at the the this fiddle

Related

How to update scope variable value in view after http call?

I am making my first project using Angularjs 1.4.3.
In my controller I am making a http request, in the success method of this http request I am updating a scope variable. In http call I am getting the latest values but in the view side its not updating the values.
Plunker Link (#rupesh_padhye thanks). (Since it is calling the servlet action, so no data will be shown in Plunker)
app.controller('measuresCtrl', ['$scope', '$modal', '$http', function($scope, $modal, $http) {
$scope.groups = []
$scope.loadAllMeasure = function() {
$http.get("fetchAllMeasure")
.success(function(data) {
console.log("Before insert");
console.log($scope.groups);
$scope.groups = data.measures;
console.log("After insert");
console.log($scope.groups);
})
.error(function() {
});
};
$scope.loadAllMeasure();
$scope.submit = function (form) {
$http({
method: 'POST',
url: 'saveMeasure',
data: {
id: form.id,
name: form.name,
description: form.description
},
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).success(function(data, status, headers, config) {
$scope.loadAllMeasure();
}).error(function(data, status, headers, config) {
});
}
})
And whenever I am performing any CRUD operation on measures I am calling a method $scope.loadAllMeasure();. But its not updating the values in the view (jsp) page.
I have tried $scope.$apply method but I am getting Error: $digest already in progress.
When I printed the value for $scope.groups using console.log inside success method, then its showing the latest values.
In my view (jsp) page I am just using ng-repeat function to show all the records in table format.
Code for my view page (minimal code) -
<div ng-repeat="group in groups | orderBy:'name'">
<div>
<input type="checkbox" id="checkbox-{{group.id}}" class="ui-checkbox" /><label for="checkbox-{{group.id}}">{{group.name}}</label>
</div>
<div>{{ group.description}}</div>
<div>
<div class="fa fa-pencil button" data="{{group.id}}" id="{{::elementId}}" ng-click="showEditForm(group.id, $event)"></div>
<div class="fa fa-trash button" data="{{group.id}}" ng-click="deleteGroup(group.id)"></div>
<div class="fa fa-clone button" data="{{group.id}}" id="{{::elementId}}" ng-click="showCloneForm(group.id, $event)"></div>
</div>
</div>
Values in console.log are
Before insert
Object { id=1, description="Measure Description1", name="Demo"}]
And
After Insert
[Object { id=1, description="Measure Description1", name="Demo"}, Object { id=2, description="Description2", name="Demo2"}]
How to update scope variable value in view after http call?
After assigning the new data to a $scope variable call:
$scope.$digest();
This will update the current scopes values
reference here: https://docs.angularjs.org/api/ng/type/$rootScope.Scope
I cant see anything wrong with your example code.
I have created a JSFiddle to try and help you.
The server call has been replaced by a setTimeout function that returns a promise.
Please see JSFiddle https://jsfiddle.net/sjwkbzxa/
Please see example below:
<div data-ng-controller="TestController as vm">
<button data-ng-click="loadAllMeasure()">Load List from Server</button>
<ul>
<li data-ng-repeat="group in groups | orderBy:'name'">
<span>{{group.description}}</span>
</li>
</ul>
</div>
The javascript:
angular.module('application',[]).controller("TestController", ['$scope', '$q', function($scope, $q){
$scope.groups = [{ id:1, description:"Initial List", name:"Demo"}];
$scope.loadAllMeasure = function(){
loadData().then(function(data){
$scope.groups = data;
});
};
function loadData(){
var deferred = $q.defer();
setTimeout(function(){
var data = [{ id:1, description:"Measure Description1", name:"Demo"}, { id:2, description:"Description2", name:"Demo2"}];
deferred.resolve(data);
}, 3000);
return deferred.promise;
}
}]);
Maybe you are missing something on your side that we cant see?
I'm a little late to answer this, but here are my 2 cents:
A simple assignment of the server data (response.data) to a $scope object didnt seem to work for me
$scope.something = response.data //didn't work
So, I returned a promise object from the service into the controller and then use
angular.copy(response.data,$scope.something)
to copy the values returned from the server. You could also pass the $scope.something to the service as a parameter to the function and have angular.copy in the service function as well, but i don't know if it's a good practise to do that.
$scope.loadAllMeasure = function() {
CalltoServer();
};
CalltoServer = function() {
return $http.get("fetchAllMeasure")
.success(function(data) {
$scope.groups = data.measures;
})
.error(function() {
});
}
try this , the success will be after 2 or 3 seconds so i guess inside the event it takes rist to bind
Hey I also faced the same issue and if anyone is still looking, it is caused by change in the $scope variable inside the $http. I think a new $scope is being created inside the success function(some prototypical inheritance stuff).
So make a copy of the variable $scope, something like
var s = $scope;
and then change
s.groups = someData;
Your code:
app.controller('measuresCtrl', ['$scope', '$modal', '$http', function($scope, $modal, $http) {
var s = $scope;
$scope.groups = []
$scope.loadAllMeasure = function() {
$http.get("fetchAllMeasure")
.success(function(data) {
console.log("Before insert");
console.log($scope.groups);
s.groups = data.measures;
console.log("After insert");
console.log($scope.groups);
})
.error(function() {
});
};
$scope.loadAllMeasure();
$scope.submit = function (form) {
$http({
method: 'POST',
url: 'saveMeasure',
data: {
id: form.id,
name: form.name,
description: form.description
},
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).success(function(data, status, headers, config) {
$scope.loadAllMeasure();
}).error(function(data, status, headers, config) {
});
}
})

AngularJS : directive does not update scope after $http response in parent scope

I got this directive:
.directive('studentTable', [function() {
return {
restrict: 'A',
replace: true,
scope: {
students: "=",
collapsedTableRows: "="
},
templateUrl: 'partials/studentTable.html',
link: function(scope, elem, attrs) {
...
}
}
}
Template:
<table class="table">
<thead>
<tr>
<th><b>Name</b></th>
<th><b>Surname</b></th>
<th><b>Group</b></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="student in students track by $index">
<td>{{ student.name }}</td>
<td>{{ student.surname }}</td>
<td>{{ student.group }}</td>
</tr>
</tbody>
</table>
Use directive in my html like this:
<div student-table students="students"
collapsedTableRows="collapsedTableRows"></div>
And the parent controller:
.controller('SchoolController', ['$scope', 'User', function($scope, User){
$scope.students = [];
$scope.collapsedTableRows = [];
$scope.search = function(value) {
if(value) {
var orgId = $state.params.id;
var search = User.searchByOrg(orgId, value);
search.success(function (data) {
$scope.students = data;
$scope.collapsedTableRows = [];
_(data).forEach(function () {
$scope.collapsedTableRows.push(true);
});
});
}
}
}])
Now at the beginnig, the table is empty, because no users in students array. After I click search, and get list of students object, I put them to scope variable, but the directive does not update, neither it find change in model (scope.$watch('students',...). What am I missing?
P.S. If I simulate the data using $httpBackend, directive works as it should.
Please make sure that data object returning array of student because somtimes you have to use data.data that simple demo should helps you:
http://plnkr.co/edit/UMHfzD4oSCv27PnD6Y6v?p=preview
$http.get('studen.json').then(function(students) {
$scope.students = students.data; //<-students.data here
},
function(msg) {
console.log(msg)
})
You should try changing the controller this way
...
$scope.$apply(function() {
$scope.students = data;
})
...
This will start a digest loop, if it's not already in progress.
Another form that will do almost the same thing is this:
...
$scope.students = data;
$scope.$digest()
...
PS:
The first method is just a wrapper that execute a $rootScope.$digest() after evaluating the function, considering that a $digest evaluates the current scope and all it's children calling it on the $rootScope is pretty heavy.
So the second method should be preferred if it works.

How to properly iterate over an array elements with Angular JS?

I want to render a table adding row per each objects in an array.
I got a Controller like:
app.controller('SignUpController',function ($scope, $http) {
var that = this
that.users = []
that.queryUsers = function() {
console.log("I'm being triggered")
$http.get("/existingUsers").
success(function (data,status,headers,config) {
console.log(data)
that.users = data
console.log(that.users)
}).
error(function (data,status, headers, config) {
console.log(status)
})
}
})
And the table markup:
<table class="table table-bordered">
<th ng-repeat="th in ['mail','Administrador','Miembro desde']">{{th}}</th>
<tr ng-repeat="p in signup.users">
<td>{{p._id}}</td>
<td>{{p.mail}}</td>
<td>{{p.admin}}</td>
</tr>
</table>
Ttable is within a div with ng-controller="SignUpController as signup". When I click a button I trigger queryUsers actually seein results in browser console:
[Object, Object, Object, Object, Object, Object, Object, Object, Object, Object]
Both mail and _id are existing attributes per each object.
So the AJAX is being done and the array I should be iterating and rendering to HTML rows actually exists and is populated, but no rows are shown.
Why?
Edit
I tried not modifying the scope:
app.controller('SignUpController', function ($scope,$http) {
$scope.users = []
$scope.queryUsers = function() {
console.log("I'm being triggered")
$http.get("/existingUsers").
success(function (data,status,headers,config) {
console.log(data)
$scope.users = data
console.log($scope.users)
}).
error(function (data,status, headers, config) {
console.log(status)
})
}
})
<div class="tab-pane" id="usecase11" ng-controller="SignUpController">
<h3>Colaboradores</h3>
<div class="row">
<div class="col-sm-6">
<table class="table table-bordered">
<th ng-repeat="th in ['mail','Administrador','Miembro desde']">{{th}}</th>
<tr ng-repeat="p in users">
<td>{{p._id}}</td>
<td>{{p.mail}}</td>
<td>{{p.admin}}</td>
<td style="border:none;"><a class="close" ng-click="">$</a></td>
<td style="border:none;"><a class="close" ng-click="">*</a></td>
</tr>
</table>
</div>
</div>
</div>
However, again I can see such array printed at browser console but nothing rendered to HTML
Here is the evidence that queryUsers is being called and that $scope.users is getting something after it.
Something interesting is that I got: {{users}} right after the table and it's displaying an empty array.
Just in case this is the GET handling server code:
app.get('/existingUsers',function (request, response) {
membersCollection.find({},{"password":0}, function (err, data) {
if (err) response.send(404)
else {
data.toArray(function (err, docs) {
if (err) {
console.log(error)
response.send("Error")
}
response.send(JSON.stringify(docs, null, 4))
})
}
})
}
You don't modify the $scope. Here is the corrected code:
app.controller('SignUpController',function ($scope, $http) {
$scope.users = []
$scope.queryUsers = function() {
console.log("I'm being triggered")
$http.get("/existingUsers").
success(function (data,status,headers,config) {
console.log(data)
$scope.users = data
console.log($scope.users)
}).
error(function (data,status, headers, config) {
console.log(status)
})
}
})
HTML:
<table class="table table-bordered">
<th ng-repeat="th in ['mail','Administrador','Miembro desde']">{{th}}</th>
<tr ng-repeat="p in users">
<td>{{p._id}}</td>
<td>{{p.mail}}</td>
<td>{{p.admin}}</td>
</tr>
</table>

How to process an array with AngularJS?

I have an API returning the following simple JSON array:
[
"efd98ad-first_key",
"100eb0a-second_key"
]
I am trying to render this as a table with Angular:
<div name="listkeys" class="container">
<div class="starter-template">
<div ng-bind-html="message"></div>
<table class="table table-striped table-bordered table-condensed sortable" ng-init="getKeys()">
<tr>
<th>bucket</th>
</tr>
<tr ng-repeat="bucket in buckets">
<td>{{bucket}}</td>
</tr>
</table>
</div>
</div>
JS:
var app = angular.module('flipDaSwitch', ['ngSanitize']);
app.controller('ListKeys', function($scope, $http) {
$scope.getKeys = function() {
$http.get('/api/keys').
success(function (data) {
$scope.response = data;
}).
error(function (data){
$scope.response = {}
});
};
});
It does not do anything but throwing an "Uncaught object" error and that is it.
How could I debug why it is failing?
You are storing the values in $scope.response, but you are using $scope.bucket at the ng-repeat:
$scope.getKeys = function() {
$http.get('/api/keys').
success(function (data) {
$scope.buckets= data;
}).
error(function (data){
$scope.buckets= {}
});
};
It looks like you do not have a scope item called buckets. I'd expect to see:
$scope.buckets = data
Inside the success callback.

AngularJS model is populated in javascript but empty on the page

I've got this code...
Agencyapp.factory('AgencyData', function ($http, $log) {
return {
getAgencies: function(successcb){
$http({ method: 'GET', url: 'http://localhost/MappingServicesWebAPI/api/mapping' }).
success(function(data){
successcb(data);
}).
error(function(data){
$log.warn(data, status, headers, config);
})
}
}
});
Which gets data from a WebAPI. The $scope.Agencies model gets populated with an AgencyList array. When I try to use that array...
<div ng-controller="AgenciesCtrl">
<select ng-model="Agencies">
<option>Select Agency</option>
<option ng-repeat="A in Agencies" >{{A.AgencyList.AgencyName}}</option>
</select>
{{Agencies.AgencyList}}
</div>
It's empty...can someone help me with what I might be doing wrong?
Here's the controller, sorry I thought I included it...
Agencyapp.controller('AgenciesCtrl', function AgenciesCtrl($scope, AgencyData) {
AgencyData.getAgencies().then(function (rtnAgencies) {
$scope.Agencies = rtnAgencies;
});
});
I tried to post a picture of the populated $scope object but I don't have enough reputation points...
It Looks like this(each indent is a nested object)...
$scope.Agencies
[prototype]
AgencyList[]
[0]
[prototype]
AgencyID -10168
AgencyName "#1 Insurance Agency"
If I hard code data...
function AgenciesCtrl($scope, AgencyData) {
$scope.Agencies = [
{
AgencyID: 'Test One',
AgencyName: 'Agency Test 1'
},
{
AgencyID: 'Test Two',
AgencyName: 'Agency Test 2'
}];
};
It Works
If I hard code data inside the function call
function AgenciesCtrl($scope, AgencyData) {
AgencyData.getAgencies().then(function (rtnAgencies) {
$scope.Agencies = [
{
AgencyID: 'Test One',
AgencyName: 'Agency Test 1'
},
{
AgencyID: 'Test Two',
AgencyName: 'Agency Test 2'
}];
});
};
It doesn't work
I haven't seen one good example of using data from a web api...all examples I have seen hard code data, what's the point in that?
First, remove ng-model="Agencies" from your <select> element. You dont want to bind your select element to the same object that you are running an ng-repeat on. Try something like <select ng-model="selectedAgency" > instead.
Second, I suggest utilizing angular's deferred API to return a promise, which will then be resolved with the value of the data returned from the server, when it is finished:
Agencyapp.factory('AgencyData', function ($http, $log, $q) {
return {
getAgencies: function(successcb){
var deferred = $q.defer();
$http({ method: 'GET', url: 'http://localhost/MappingServicesWebAPI/api/mapping' }).
success(function(data){
deferred.resolve(successcb(data)); //I dont know what successcb() does
}).
error(function(data){
deferred.reject(data);
$log.warn(data, status, headers, config);
})
return deferred.promise;
}
};
});
In your controller, you would then do something like this:
AgencyData.getAgencies().then(function(data) {
$scope.Agencies = data;
});
As soon as the getAgencies() function finishes getting the data, the $scope.Agencies object will be updated with the resulting data.
It turns out I had my...
<div ng-controller="AgenciesCtrl">
<select ng-model="Agencies">
<option>Select Agency</option>
<option ng-repeat="A in Agencies" >{{A.AgencyList.AgencyName}}</option>
</select>
{{Agencies.AgencyList}}
</div>
Inside a that was controlled by a Javascript Library called Slidebox.js.
Once I removed Slidebox.js everything worked correctly.

Categories