I am using service to get JSON object using promises. It is then converted into array and assign to a property which is in $scope object. The problem is that array is not getting updated or any properties inside promise then() method.
Controller
var searchController = function ($scope, $SPJSOMService) {
$scope.myName = "old name";
$scope.getUsers = function ($event) { //called on button click
$event.preventDefault();
var queryText = "test user";
$SPJSOMService.getUsers(queryText)
.then(function myfunction(users) {
$scope.userCollection = JSON.parse(JSON.stringify(users)).d.results;
// $scope.$apply(); this line throwing error. $rootScope in progress
$scope.myName = "new name"; //not getting updated
}, function (reason) {
alert(reason);
});
};
};
Service
var SPJSOMService = function ($q, $http, $rootScope) {
this.getUsers = function (userToSerach) {
var deferred = $q.defer();
$http({
url:'some url',
method: "GET",
headers: {
"accept": "application/json;odata=verbose",
"content-Type": "application/json;odata=verbose"
}
})
.success(function (data, status, headers, config) {
deferred.resolve(data); //successfully return data
})
.error(function (data, status, headers, config) {
deferred.reject(data);
});
return deferred.promise;
};
};
Updated
index.html
<div ng-include="'Search.html'">
</div>
<div ng-include="'searchResults.html'"></div>
search.html
<div id="containerDiv" ng-controller="searchController as search">
<input class="button" type="button" ng-click="getUsers($event);" value="Search" id="btnSearch" />
</div>
searchResults.html
<div ng-controller="searchResultController as result">
<table >
<thead>
<tr>
<th>Name</th>
<th>EMail</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in userCollection">
<td>{{$index}} {{item.userName}}</td>
<td>{{$index}} {{item.userEmail}}</td>
</tr>
</tbody>
</table>
</div>
So search.html returns the data by calling the service and I am trying to pass it to the page namely searchResults.html which have its own controller.
$scope.users = $scope.userCollection;
Service class correctly returning data, but the problem is inside then(), which is not updating $scope.userCollection, hence UI is not getting updated.
Please help me out, what am I missing here.
In angular controllers can bind to the view in two ways:
"controller as"
through scope
It looks you are using the "controller as" flavor here...
<div ng-controller="searchResultController as result">
Refer to https://docs.angularjs.org/api/ng/directive/ngController for more information.
Change your controller code to:
var searchController = function ($scope, $SPJSOMService) {
//note use of "this" instead of "$Scope"
var _this = this;
_this.myName = "old name";
_this.getUsers = function ($event) { //called on button click
$event.preventDefault();
var queryText = "test user";
$SPJSOMService.getUsers(queryText)
.then(function myfunction(users) {
_this.userCollection = users.d.results; //You don't need JSON.parse not JSON.stringify
_this.myName = "new name";
}, function (reason) {
alert(reason);
});
};
};
and in your view use the controller "alias":
<div ng-controller="searchResultController as result">
...
<tr ng-repeat="item in result.userCollection">
...
You have to push it to the new array I think. Have you tried this in your then statement?
$scope.myName.push("new name");
It should put it in the existing array. Let me know if it works.
Related
I want to get status value from API in my grid made in angular js. Below is the code, I applied in my view file:
<tr ng-repeat="item in list">
<td>{{item.id}}</td>
<td class="text-center" ng-init="statusUpdate(item.id ,$index)">
</td>
<td>{{myVar[$index]}}</td>
</tr>
Then in my controller I added:
app.controller('MerchantController', function ($scope, MerchantService, Alert, toaster) {
$scope.statusUpdate = function (id, index) {
var api = MerchantService.statusUpdate(id, index).then(function (response) {
console.log($scope.myVar[index]);
$scope.myVar[index] = response.data;
console.log($scope.myVar[index]);
});
};
});
In my service file, I added:
app.service('MerchantService', function(API, $stateParams, $q,$http) {
this.statusUpdate = function(item,index) {
return $http({
url: 'http://10.10.10.7/petca_magento/integration/vendor/vendor/id/' + item,
method: "GET",
});
};
});
I want to get of status field dynamically based on the user id in {{myVar[$index]}}
Title might sound a bit strange but that's how it is.
Code:
angular.module('app')
.controller('TenantsCtrl', ['$scope', 'tenantsService','$window','loginService', function ($scope, tenantsService, $window, loginService) {
$scope.mode = "list";
$scope.g = [];
$scope.editTenant = {
firstName: "",
lastName: "",
room: "",
to: "",
from: ""
}
tenantsService.get().then((data) => {
data.tenants.map((tenant) => {
tenant.to = new Date(tenant.to).toLocaleDateString('ro-RO')
tenant.from = new Date(tenant.from).toLocaleDateString('ro-RO')
});
console.log(typeof data.tenants);
$scope.g = data.tenants;
console.log($scope.g)
}).catch((reason) => {
loginService.doLogout();
if(confirm(`${reason}. Please login`)) {
$window.location.href="#!/login";
}
})
$scope.showTenantForm = function(tenant) {
console.log($scope.g)
}
}]);
View:
<div class="page-header">
<h1>Cazati <button class="btn btn-xs btn-primary" ng-click="showTenantForm()">Cazeaza</button></h1>
</div>
<div class="row" ng-cloak>
{{g}}
<table class="table table-hover">
<thead>
<tr>
<th>Nume</th>
<th>Camera</th>
<th>Cazat din</th>
<th>Cazat pana la</th>
<th>Cazat de</th>
<!--<th>Status</th>-->
<th>Modifica</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="x in g">
<td>{{x.lastName}} {{x.firstName}}</td>
<td>{{x.room}}</td>
<td>{{x.to}}</td>
<td>{{x.from}}</td>
<td></td>
<td>
<button type="button" ng-click="editTenant(tenant.id)" class="btn btn-danger btn-xs">Modifica</button>
</td>
</tr>
</tbody>
</table>
</div>
Problem: data from table isn't shown. Strangely it gets shown only when press the button from header and the function gets called.
Data from service comes correctly.
Update: tenantsService
angular.module('app')
.service('graphQLService', ['baseUrl', 'loginService', function (baseUrl, loginService) {
var graphQLService = {};
graphQLService.sendQuery = function (query, vars) {
var self = this;
vars = vars || {};
return new Promise(function(resolve, reject) {
// use fetch to get the result
fetch(baseUrl + '/gql', {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
query,
vars,
authToken: loginService.getToken()
})
})
.then(function(response) {
var status = response.status;
if(status != 401) {
return response.json().then((res) => {
resolve(res.data);
})
} else {
reject(response.statusText);
}
if(response.status == 401) {
}
})
.catch(reject);
});
};
return graphQLService;
}]);
Add a $scope.$apply() after you get your response and you manipulate your data, and after that you assign your data to your g scope variable. So:
$scope.g = data.tenants;
$scope.$apply();
AngularJS already wraps a lot of its code inside the $scope.$apply method. This in order to trigger the $scope.$digest method, which is the one responsible for refreshing all the bindings inside the related scope and update the values and so the views.
For example, if you were using the custom $http service, it's executed inside the $scope.$apply, so you don't need to call it explicitly.
In your case, you are not using the standard $http, so you need to trigger it manually.
The code was working after calling the other function because the ng-click is wrapped inside the $apply as well, so it refreshes all the bindings in the scope.
If you want to read more about it, this is a pretty good article:
http://jimhoskins.com/2012/12/17/angularjs-and-apply.html
I hope it helps
I think the problem is that data.tenants.map returns you a new array. You don't save the reference to it.
Have you tried to do this
$scope.g = data.tenants.map((tenant) => {
tenant.to = new Date(tenant.to).toLocaleDateString('ro-RO');
tenant.from = new Date(tenant.from).toLocaleDateString('ro-RO');
return tenant;
});
console.log(typeof data.tenants);
console.log($scope.g)
hi i am creating a application with Angularjs,REST service with spring. i want to pass the object from angulajs url to rest service , but it does work, please any one help me, my jsp page code is like below,
<html ng-app="studentApp">
<body>
<div ng-controller="studentController">
<table border = "0">
<tr>
<td>Enter first name:</td>
<td><input type = "text" ng-model = "student.firstName"></td>
</tr>
<tr>
<td>Enter last name: </td>
<td>
<input type = "text" ng-model = "student.lastName">
</td>
</tr>
</table>
</div>
</body>
</html>
and my angularjs code is,
var studentApp = angular.module("studentApp", []);
studentApp.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}]);
studentApp.controller("studentController", [ '$scope', '$http',
function($scope, $http) {
$scope.toggle=true;
var urlBase="http://localhost:8080/studentweb/";
$scope.insertStudent = function inserStudent() {
$http({
method : 'POST',
url : urlBase+'/Student/insert',
data: {student:data}
}).success(function(data, status, headers, config) {
$scope.student=data;
$scope.toggle='!toggle';
}).error(function(data, status, headers, config) {
alert( "failure1");
});
and my rest service is,
public class StudentController
{
#RequestMapping(value="/Student/insert",method = RequestMethod.POST ,params= {"student"})
public String insertStudent(#RequestParam("student") StudentVO student) throws ParseException {
student.setFirstName(student.getFristName());
student.setLastName(student.getLstName());
studentcontrol.addStudent(student);
return "";
}
}
} ])
The problem is that you "usrlBase" variable has "student/" extra as you are already calling your Student controller in
url : urlBase+'/Student/insert'
Hence the complete URL becomes something like
http://localhost:8080/student//Student/insert whereas it should be something like:
http://localhost:8080/Student/insertStudent
Update:
Below is an absolutely fine working example with a sample restful service you had some brackets missing in your code. Please go through the below code and get back to me if required.
<html ng-app="studentApp">
<div ng-controller="studentController">
<table border="0">
<tr>
<td>Enter first name:</td>
<td><input type="text" ng-model="student.FirstName"></td>
</tr>
<tr>
<td>Enter last name: </td>
<td>
<input type="text" ng-model="student.LastName">
</td>
</tr>
</table>
</div>
Script:
var studentApp = angular.module("studentApp", []);
studentApp.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}]);
studentApp.controller("studentController", ['$scope', '$http',
function ($scope, $http) {
$scope.toggle = true;
//var urlBase = "http://localhost:8080/student/";
// $scope.insertStudent = function () {
debugger;
$http({
method: 'GET',
url: 'http://services.odata.org/V4/Northwind/Northwind.svc/Employees(1)?$format=json',
// data: { student: data }
}).success(function (data, status, headers, config) {
debugger;
$scope.student = data;
$scope.toggle = '!toggle';
}).error(function (data, status, headers, config) {
debugger;
alert("failure1");
});
// }
}]);
Does anyone have a decent example with ng-table loading data upon a success callback from http service?
this.getData = function(){
tmp = this;
tmp.loading = true;
$http.post('/fetch',
$.param({
service_request: JSON.stringify(this.session)
}
)).success(function(data) {
tmp.loading = false;
tmp.tableData = data;
});
};
I would like to build the table from the tableData variable.
Thanks
I think this is one way of doing it.
Create a service to get the table data (I just picked the code from your :
app.factory('getTableData', function($http) {
return {
getData: function(session){
return $http.post('/fetch',
{
service_request: session
}))
}
}
})
Then you inject the service in your controller:
app.controller('DemoCtrl', function(getTableData, $scope, $window) {
$scope.loadTable = function(){
getTableData.getData(JSON.stringify($window.session)) //not sure where you have the session variable stored.
.sucess(function(data){
$scope.tableData = data;
})
.error(function(){
//do something
})
}
})
The HTML should be pretty straightforward:
<button ng-click="loadTable()">Load Table</button>
<table ng-table class="table">
<tr ng-repeat="row in tableData">
<td data-title="'Property1'">{{row.Property1}}</td>
<td data-title="'Property2'">{{row.Property2}}</td>
</tr>
</table>
In my angular app I have a controller as follows:
function TemplateListControl($scope, TemplateService){
$scope.templates = TemplateService.get(); // Get objects from resource
// Delete Method
$scope.deleteTemplate = function(id){
$scope.templates.$delete({id: id});
}
}
Within the view I have a table thats bound to templates model. as follows:
<table ng-model="templates">
<thead>
<tr>
<th style="width:40%">Title</th>
<th style="width:40%">controls</th>
</tr>
<thead>
<tbody>
<tr ng-repeat="template in templates">
<td>
<!-- Link to template details page -->
<a href="#/template/[[template.id]]">
[[template.title]]
</a>
</td>
<td>
<!-- Link to template details page -->
<a class="btn btn-primary btn-small"
href="#/template/[[template.id]]">Edit
</a>
<!-- Link to delete this template -->
<a class="btn btn-primary btn-small"
ng-click="deleteTemplate(template.id)">Delete
</a>
</td>
</tr>
</tbody>
</table>
Now when I click on the delete link in the above template, It calls the deleteTemplate method and a successful DELETE call is made to the REST api. But the view does not get updated until it is refreshed and $scope.templates = TemplateService.get(); is initiated again. What am I doing wrong?
I prefer using promises instead of callback. Promises are the new way to handle asynchronous processes. You can inspect the result using a a promise right after it came back from the server.
//Controller
myApp.controller('MyController',
function MyController($scope, $log, myDataService) {
$scope.entities = myDataService.getAll();
$scope.removeEntity = function (entity) {
var promise = myDataService.deleteEntity(entity.id);
promise.then(
// success
function (response) {
$log.info(response);
if (response.status == true) {
$scope.entities.pop(entity);
}
},
// fail
function (response) {
$log.info(response);
// other logic goes here
}
);
};
});
//DataService
myApp.factory('myDataService', function ($log, $q, $resource) {
return {
getAll: function () {
var deferred = $q.defer();
$resource('/api/EntityController').query(
function (meetings) {
deferred.resolve(meetings);
},
function (response) {
deferred.reject(response);
});
return deferred.promise;
},
deleteEntity: function (entityId) {
var deferred = $q.defer();
$resource('/api/EntityController').delete({ id: entityId},
function (response) {
deferred.resolve(response);
},
function (response) {
deferred.reject(response);
});
return deferred.promise;
}
};
});
//Web API Controller
public class MeetingController : BaseApiController
{
// .... code omited
public OperationStatus Delete(int entityId)
{
return _repository.Delete(_repository.Single<MyEntity>(e => e.EntityID == entityId));
}
}
Note: $log, $q, $resource are built in services. Hope it helps :)
You also have to update client side so modify your source code as below
ng-click="deleteTemplate($index)">
$scope.delete = function ( idx ) {
var templateid = $scope.templates[idx];
API.Deletetemplate({ id: templateid.id }, function (success) {
$scope.templates.splice(idx, 1);
});
};
You could pass a callback function to $resource.$delete
function TemplateListControl($scope, TemplateService){
$scope.templates = TemplateService.get(); // Get objects from resource
// Delete Method
$scope.deleteTemplate = function(id){
TemplateService.$delete({id: id}, function(data) {
$scope.templates = data;
});
}
}
Attention
If your REST APIs delete function returns an array you have to set isArray: true in your Angular $resource to avoid a AngularJS $resource error - TypeError: Object # has no method 'push'
$resource(URL, {}, {
delete: {method:'DELETE', isArray: true}
});