angular deleting a row in a table - angularjs

I'm trying to delete a row in a table generated using angular ng-repeat directive and I get a "DELETE http://localhost:3000/api/delbike 404 (Not Found)" error. I suspect this to be an issue at the server end, but I'm also not getting the parameter to be passed to the $http service on angular end. Any help will be greatly appreciated. I expect $scope.bikes[idx] to pass the bike object selected for deletion. however while debugging it shows as undefined.Below is the angular code
//controller
ub.controller('bikectrl',["$scope","fbauthFact","$log","bike",function($scope,fbauthFact,$log,bike){
$log.log("In bike controller");
$scope.msg = "";
$scope.bikes =[];//bikes array to store bikes retrieved for a user
$scope.bike ={};//bike object to submit details of bike
//var bike ={};
var idx;
$scope.usr = fbauthFact.getResponseobj();
bike.getbikes($scope.usr).then(function(response){
$scope.bikes = response;
},function(reason){
$scope.msg = reason;
});//getbikes
$scope.delbike = function(idx){
$scope.bikes.splice(idx,1);
bike.delbike($scope.bikes[idx]).then(function(response){
$scope.msg = response;
},function(reason){
$scope.msg = reason;
});
};
}]);
//factory
ub.service('bike',['$http','fbauthFact','$log','$q',function($http,fbauthFact,$log,$q){
var user={};
var bike={};
//retrieve bikes
this.getbikes = function(user){
var deferred = $q.defer();
$http({
method:"GET",
url:"http://localhost:3000/api/getbike",
params: user
}).then(function successCallback(srresponse){
deferred.resolve(srresponse.data);
},
function failureCallback(srresponse){
$log.error("get bikes http call failed ",srresponse.data);
deferred.reject(srresponse.data);
});//$http
return deferred.promise;
};//getbikes
//delete bike
this.delbike = function(bike){
var deferred = $q.defer();
$http({
method:"DELETE",
url:"http://localhost:3000/api/delbike",
params: bike
}).then(function successCallback(srresponse){
deferred.resolve(srresponse.data);
},function failureCallback(srresponse){
deferred.reject(srresponse.data);
});
return deferred.promise;
};//delbike
}]);
//html
<div>
<div class='container' style='margin-top:90px;'>
<div class='row'>
<div class='col-md-8'>
<h3>Bikes of {{usr.first_name}}. Click here to add</h3>
</div>
</div>
</div>
<div class='container'>
<div class='table-responsive'>
<table class='table table-hover'>
<thead>
<tr>
<th>#</th>
<th>Make</th>
<th>Regno</th>
<th>Model</th>
<th>Year</th>
<th>Delete?</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="x in bikes">
<td>{{$index+1}}</td>
<td>{{x.brand}}</td>
<td>{{x.regno}}</td>
<td>{{x.model}}</td>
<td>{{x.year}}</td>
<td>
<button type="button" ng-click="delbike($index)" class="btn btn-default btn-sm">
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
</button>
</td>
</tr>
</tbody>
</table>
</table>
</div>
</div>
//server side snippet
app.delete('/api/delbike/*',function(req,res){
ubBike.remove({regno:req.query.regno},function(err,results){
if(err) throw err;
if(results.result.n==0)
{
res.send('Bike not registered');
}
else
{
res.send('Success');
}
});
});

Not sure about the first case of getting 404 not found
http://localhost:3000/api/delbike
It might be the server side issue or something buggy
but for the second case:
It will be undefined as you're removing it using this
$scope.bikes.splice(idx,1);
Before sending it to service for further processing
Try writting above block inside the resolver of the delete call
So you delbike method inside controller will look like following
$scope.delbike = function(idx){
bike.delbike($scope.bikes[idx]).then(function(response){
$scope.msg = response;
$scope.bikes.splice(idx,1); // add it here
},function(reason){
$scope.msg = reason;
});
};

Please checkout is your server side method type is HTTPDELETE or POST?
If it is POST Method then you need to change your Method type on your HTTP call
change method:"POST", it instead of method:"DELETE",
Also you don't need $scope.bikes.splice(idx,1); delete the object in the array, because the server also return deleted results.

I was able to resolve the issue by removing the slash '/' a the end of the router url in the api
app.delete('/api/delbike*',function(req,res){..

Related

$resolved: false in Angular JS response

I'm setting up an Angular JS app that consumes a Django REST API.
I want to show a HTML list of classrooms.
This is my template
<body>
<div ng-app="schoolApp" ng-controller="schoolCtrl">
<table class="table table-striped">
<thead>
<tr>
<th>Classroom</th>
<th>School</th>
<th>Floor</th>
<th>Academic year</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="classroom in classrooms">
<td>{{classroom.classroom}}</td>
<td>{{classroom.school.school_name}}</td>
<td>{{classroom.floor}}</td>
<td>{{classroom.academic_year}}</td>
</tr>
</tbody>
</table>
</div>
</body>
This is the script
var schoolApp = angular.module('schoolApp', ['ngResource']);
schoolApp.factory('Classroom', ['$resource', function($resource) {
return $resource('/classrooms/?format=json', {}, {
query: {
method: 'GET',
isArray: true,
}
});
}]);
schoolApp.controller('schoolCtrl', function($scope, Classroom) {
Classroom.query().$promise.then(function(data) {
var data = Classroom.query({});
$scope.classrooms = data;
console.log(Classroom.query({}));
});
});
The problem is, I think, that I get - I can see it in the console -, $resolved: false.
How can I resolve that?
UPDATE:
Given that I can't resolve the issue, I was wondering that maybe I've set up badly something else, like... the view?
This is the one I got
class HomePageView(TemplateView):
template_name = 'school_app/base.html'
class StudentViewSet(viewsets.ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentSerializer
class ClassroomViewSet(viewsets.ModelViewSet):
queryset = Classroom.objects.all()
serializer_class = ClassroomSerializer
Maybe I have to add something to HomePageView or setting it up in another way?
UPDATE:
This is what I get on the console with the debugger "on"
Success: [{"school":{"id":1,"school_name":"IPSIA F. Lampertico","address":"Viale Giangiorgio Trissino, 30","city":"Vicenza"},"academic_year":"2015/2016","classroom":"1^A","floor":0,"students":[{"classroom":1,"first_name":"Stefano","last_name":"Rossi","gender":"M","birthday":"1998-06-22"},{"classroom":1,"first_name":"Luca","last_name":"Possanzini","gender":"M","birthday":"1999-11-22"}]},{"school":{"id":2,"school_name":"ITIS A. Rossi","address":"Via Legione Gallieno, 52","city":"Vicenza"},"academic_year":"2015/2016","classroom":"2^B","floor":0,"students":[{"classroom":2,"first_name":"Sergio","last_name":"Lazzari","gender":"M","birthday":"2001-01-29"}]},{"school":{"id":3,"school_name":"Liceo Scientifico G.B. Quadri","address":"Viale Giosuè Carducci, 17","city":"Vicenza"},"academic_year":"2015/2016","classroom":"3^C","floor":0,"students":[{"classroom":3,"first_name":"Lucia","last_name":"Modella","gender":"F","birthday":"2000-05-22"}]},{"school":{"id":4,"school_name":"Istituto Professionale Statale B.Montagna","address":"Via Mora, 93","city":"Vicenza"},"academic_year":"2015/2016","classroom":"4^D","floor":1,"students":[{"classroom":4,"first_name":"Mirko","last_name":"Van Der Sella","gender":"M","birthday":"2002-12-25"}]}]
Practically, the whole Json response.
When you call query of $resource, it returns a reference to an object or array with $resolved = false, until the REST API calls finishes and populates your object. So, $resolved = false is probably correct and indicates that you have not receive the data yet.
Here is a working plunker based on your code.
The controller is:
app.controller('schoolCtrl', function($scope, Classroom) {
var vm = this;
vm.name = 'World';
Classroom.query().$promise.then(function(data) {
console.log('Success: '+JSON.stringify(data));
vm.classrooms = data;
}, function (reason) {
console.log('ERROR: '+JSON.stringify(reason));
});
});
This is what I do for debugging REST web API... once the call works, you can switch to a lighter version:
app.controller('schoolCtrl', function($scope, Classroom) {
var vm = this;
vm.name = 'World';
vm.classrooms = Classroom.query();
});
I created a classroom JSON (guessing your format):
[
{"classroom":"0", "school": {"school_name":"anc"} },
{"classroom":"1", "school": {"school_name":"Sorbonee"} }
]
And the HTML:
<body ng-controller="schoolCtrl as vm">
<p>Hello {{vm.name}}!</p>
<div>
<table class="table table-striped">
<thead>
<tr>
<th>Classroom</th>
<th>School</th>
<th>Floor</th>
<th>Academic year</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="classroom in vm.classrooms">
<td>{{classroom.classroom}}</td>
<td>{{classroom.school.school_name}}</td>
<td>{{classroom.floor}}</td>
<td>{{classroom.academic_year}}</td>
</tr>
</tbody>
</table>
</div>
</body>
I changed the URL in the factory to make it work on plnkr, but the rest is identical:
app.factory('Classroom', ['$resource', function($resource) {
return $resource('classrooms?format=json', {}, {
query: {
method: 'GET',
isArray: true,
}
});
}]);
Please note that I use var vm=this and ControllerAs syntax to avoid any scope issues based on this article.
On ngResource from the doc: "It is important to realize that invoking a $resource object method immediately returns an empty reference (object or array depending on isArray). Once the data is returned from the server the existing reference is populated with the actual data. This is a useful trick since usually the resource is assigned to a model which is then rendered by the view. Having an empty object results in no rendering, once the data arrives from the server then the object is populated with the data and the view automatically re-renders itself showing the new data. This means that in most cases one never has to write a callback function for the action methods."
Let us know if this helps.

How get my controller to make GET request when tab is selected?

I am pretty new to angular and I am working on a data entry web page. The web page has three tabs. Vendor, Products and Types. I started working on the Types tab first. I'd be happy if I could just display the results of a GET request to my Rest API. My Rest API works:
# curl http://192.168.1.115:8080/type
[
{"_id":"56415e7703aba26400fcdb67","type":"Skiing","__v":0},
{"_id":"56417a8503aba26400fcdb68","type":"Bannana","__v":0},
{"_id":"56417a8d03aba26400fcdb69","type":"Carrot","__v":0},
{"_id":"56417a9603aba26400fcdb6a","type":"Beer","__v":0}
]
Here's the pertinent part of my html UPDATED I now have st-safe-src=all_typesbut still no joy ...
<div ng-controller="typeCtrl" class="tab-pane" id="types-v">
<p>The number {{3 + 4}}.</p>
<p>message is {{message}}</p>
<table st-table="displayedCollection" st-safe-src="all_types" class="table table-striped">
<tbody>
<tr ng-repeat="x in displayedCollection">
<td>{{x.type}}</td>
</tr>
</tbody>
</table>
</div> <!-- end Types Tab -->
... and here is my typeCtrl.js ...
app.controller("typeCtrl", function($scope,$http) {
$scope.type_to_look_for = "";
$scope.message = "this is the message. (from typeCtrl)";
$scope.itemsByPage=15;
$scope.all_types = function () {
$http.get("http://192.168.1.115:8080/type").then(function(response) {
console.log(response);
console.log(response.data);
return response.data;
});
}
});
... but when I click on the Types tab my data does not display. I looked developer console and I do not even see the GET request kickoff. And my web page looks like this ...
... what am I doing wrong?
There is nothing that calls all_types. Run http.get and assign the response to all_types
app.controller("typeCtrl", function($scope,$http) {
$scope.type_to_look_for = "";
$scope.message = "this is the message. (from typeCtrl)";
$scope.itemsByPage=15;
$http.get("http://192.168.1.115:8080/type").then(function(response) {
$scope.all_types = response;
});
}
});
My understanding is that you want a get request to be fired whenever you click on the Types tab, right? If so, just use ng-click to call your all_types function as follows:
<div ng-controller="typeCtrl" ng-click="all_types()" class="tab-pane" id="types-v" >
Also, you do not need to return response.data in your controller. Just assign the data to a scope object and use it in the template.
And finally, I would suggest wrapping all your ajax calls in factories and then inject those factories in your controllers.
Here is your code
<div ng-controller="typeCtrl" class="tab-pane" id="types-v">
<p>The number {{3 + 4}}.</p>
<p>message is {{message}}</p>
<table st-table="types" class="table table-striped"><!-- Do not need st-safe-src -->
<tbody>
<tr ng-repeat="x in types"><!-- Use the Collection name as types-->
<td>{{x.type}}</td>
</tr>
</tbody>
</table>
</div>
Controller Code
app.controller('typeCtrl', function($scope, $http) {
$scope.type_to_look_for = "";
$scope.message = "this is the message. (from typeCtrl)";
$scope.itemsByPage=15;
$http.get("http://192.168.1.115:8080/type").then(function(response) {
console.log(response.data);
$scope.types = response.data;
});
});
Here is working the plunker

2-Way-Databinding not working in AngularJS from factory with MEAN-Stack

I'm trying to build a single-page-app which lists some files from my local database (MongoDB), but AngularJS doesn't show me the data. When i get them from the Express-API via Postman, everything is ok. I get them through a controller, which calls a factory and this is getting the data. But when I delete a File from the database, AngularJS isn't updating the table. When I reload the page, it show's the correct data without the deleted item, but why isn't the 2-way-databinding working?
This is the Table-Content in my index.html:
<div ng-controller="FileCtrl">
<div ng-hide="files.length" class="alert alert-warning">Noch keine Files vorhanden!</div>
<table ng-show="files.length" class="table">
<tr>
<th>ID</th>
<th>Name</th>
<th>Path</th>
<th></th>
<th></th>
</tr>
<tr ng-repeat="file in filtered = (files | filter:searchtext | orderBy: 'name')" class="files-item">
<td>{{file._id}}</td>
<td>{{file.name}}</td>
<td>{{file.path}}</td>
<td><a href class="btn btn-default btn-sm" ng-click="fileFactory.playFile(file);">Play</a></td>
<td><a href class="btn btn-default btn-sm" ng-click="fileFactory.removeFile(file._id);">Delete</a> </td>
</tr>
</table>
</div>
And this is my app.js:
angular.module('picube', [])
.factory('fileFactory', function($http) {
var files = [];
return {
getFiles: function(callback) {
$http.get('http://localhost:8080/api/files/').then(function (Response) { //takes all files from the api, tested with postman
files = Response.data; //Update Data
callback(files);
});
},
postFile: function(filepath){
$http.post("http://localhost:8080/api/files/", filepath).then(function (Response) { //adds a new file to the server-api, tested with postman
files = Response.data; //Update Data
});
},
playFile: function(filepath){ //this is not important at the moment
console.log("Play called");
console.log(filepath);
},
removeFile: function(_id){ //deletes a file from server, tested with postman
$http.delete("http://localhost:8080/api/files/" + _id).then(function(callback){
files = callback.data; //Update Data
});
}
};
})
.controller('FileCtrl', function($scope, fileFactory) {
$scope.fileFactory = fileFactory;
init();
function init() {
fileFactory.getFiles(function(files){
$scope.files = fileFactory.files;
});
}
});
You need to use angular.copy to preserve the reference, otherwise you'll overwrite it and break two-way binding:
$http.get('http://localhost:8080/api/files/').then(function (Response) { //takes all files from the api, tested with postman
files.length = 0; // clear the array
angular.copy(Response.data, files); //Update Data
...
});
I implemented my DB handling using ngresource/$resource factory instead of $http (more info available with an example at https://docs.angularjs.org/api/ngResource/service/$resource#!).
However, it should work also ok with $http as well. I did my "removeFile"-equivalent so that I actually either read the data from the server using GET after the delete, or when data amounts get big, it is better to just use splice -method on the file[] array using index parameter - here is my proposal for modified version for you to try:
...
removeFile: function(_id, index){ //deletes a file from server, tested with postman
$http.delete("http://localhost:8080/api/files/" + _id).then(function(callback){
$scope.files.splice(index, 1);
});
}
...
and correspondingly in the .html, call to this to include $index:
...
<td>
<a href class="btn btn-default btn-sm" ng-click = "fileFactory.removeFile(file._id, $index)">Delete</a>
</td>
...
Rationale here is that I don't think your Delete -method responds with updated full files list - at least usually they don't but you must yourself update the local contents .
Hope this helps...
Okay, now it works.
The problem was the files.length = 0, which is causing the error.
The reason is, that angular.copy clears the array itself (see here: array.copy).
This works:
$http.get('http://localhost:8080/api/files/').then(function (Response) {
angular.copy(Response.data, files);
});

finish a controller treatment before execute another

i have 2 controller loaded in one page : one loaded by $routeProvider,
application.js
.when('/service/:serviceId/:serviceName/',
{
templateUrl : 'view/service/service.html',
controller : 'ServiceController'
})
the other loaded in the view
service.html
<div align="left">
<table class="table-flag">
<tr ng-controller="LanguageController">
<td ng-repeat="language in listLanguage"
width="50">
<input type="image" ng-src="img/flags/{{language.code}}.jpg"width="30" height="20"></input> </a>
</td>
</tr>
</table>
<div>
<br />
<ul>
<table class="table table-hover">
<tbody>
<tr
ng-repeat="detail in service.infoList">
<td><span ng-bind-html-unsafe="detail.label"></span></td>
</tr>
</tbody>
</table>
</ul>
</div>
</div>
I retrieve some datas from a server using rest
ServiceController
Info.controller('ServiceController', function ServiceController(
$scope, $http, $routeParams, manageDatas) {
$scope.serviceId = $routeParams.serviceId;
$scope.serviceName = $routeParams.serviceName ;
var paramsService = {
serviceId : $scope.serviceId,
serviceName : $scope.serviceName
};
$scope.loading = true;
var response = $http({
url : 'rest/service',
params : paramsService,
method : 'GET'
});
response.success(function(service) {
$scope.service = service;
$scope.loading = false;
manageDatas.setArrayData($scope.service.languageList); // service which allow to pass an array in LanguageController
});
});
LanguageController
LanguageController.controller('LanguageController', function ServiceByLanguageController(
$scope, $http, $routeParams, $timeout , manageDatas , $route) {
$scope.listLanguage = manageDatas.getDatas(); // retrieve the array passed in ServiceController by a service
// always null
});
The problem is the $http.success method in ServiceController is always executed AFTER LanguageController(verified by breakpoints) so the array $scope.listLanguage is always empty because i don t pass datas....
How can i make the languageController be executed after all the treatments in serviceController finish ?
Thank you very much
Alternatively, you can broadcast event in response.success(function(service) {...}, say, using $rootScope, and let LanguageController listen to this event and then do assignment $scope.listLanguage = ...
Just after a brief look, I would say that part or all of your ServicesController logic should be in a service and not a controller. You seem to have such a service in manageDatas. Just put all the code that actually loads and writes data to the service inside the service.

How to show value on ng-click event?

I am bit new to AngularJs and looking for help on some basic concepts.
Basically the following code correctly shows data returned from request API.
Request.cshtml
<div data-ng-controller="PostsController">
<strong class="error">{{ error }}</strong>
<strong data-ng-show="loading">loading..</strong>
<div data-ng-repeat="request in posts | orderBy: 'Id':true">
<strong>ID: {{ request.Id }}</strong>
<strong>Contact No: {{ request.ContactNumber }}</strong>
</div>
</div>
now i am further looking to add button in view and when user click on in, the contact number should be displayed.
i have written following html/angular view code.
show number
I need help in writing the corresponding "ShowNumber()" function in PostsController.js file.
But i am confused how to send single value instead of lists. Any help on it please?
here is my current PostsController.js code
function PostsController($scope, $http) {
$scope.loading = true;
$scope.editMode = false;
$http.get('/api/request').success(function (data) {
$scope.posts = data;
$scope.loading = false;
})
.error(function () {
$scope.error = "An Error has occured while loading posts!";
$scope.loading = false;
});
}
The function:
$scope.ShowNumber=function(value){
//Your logic
}
HTML
<input type="button" value="Show" ng-click="ShowNumber(request.Id)" />
You can send any value in the function.
Also you can send a index of list:
ng-click="ShowNumber($index)"

Resources