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

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

Related

angular deleting a row in a table

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){..

Angular template doesn't render data from controller

I'm setting up an Angular JS app to consume a Django REST API, and I'm stuck on the rendering of data.
I already asked another question (this), but the solution that I've been given doesn't work.
I was wondering that maybe there is something wrong in the API view, could it be a problem when trying to render the data from the Angular controller?
Anyway, this is my Angular app + template (edited as suggested in the other stackoverflow question)
base.html
<body ng-app="schoolApp" 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>
app.js
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) {
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));
});
});
I was thinking that maybe there is some problem on the view, so here's the REST API view
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
What am I doing wrong?
UPDATE:
This is what I get
Data on the console: yes.
Data on the tables: no.
As you are using controllerAs syntax, you have binded all data to controller context. So you could get data on view using its alias like vm.classrooms
<tr ng-repeat="classroom in vm.classrooms">
Have you tried to output in the html the content of the variable vm.classrooms.
You can do it with <pre>{{vm.classrooms|json}}</pre>
It seems to me that you are not binding correctly the variables inside the table,
i can't see it clearly in the picture, it can be {{ classroom.school.academic_year }} ??

function not executing on different view

I am new to angular JS. I have created a simple page using ngRoute.
In the first view I have a table, and on clicking it redirects to second view.
But I have called two functions using ng-click the changeView functions is running fine. But the second function fails to execute on the second view.
But Its running fine if using on the first view itself.
Heres the code for first view
Angular.php
<div ng-app="myApp" ng-controller="dataCtr">
<table class='table table-striped'>
<thead>
<tr>
<td>Title</td>
<td>Stream</td>
<td>Price</td>
</tr>
</thead>
<tbody>
<tr ng-repeat = "x in names | filter:filtr | filter:search" ng-click=" disp(x.id);changeView()">
<td >{{ x.Title }}</td>
<td>{{ x.Stream }}</td>
<td>{{ x.Price }}</td>
</tr>
</tbody>
</table>
</div>
heres the second View
details.php:
<div ng-app="myApp" ng-controller="dataCtr">
<div class="container">
SELECTED:<input type="textfield" ng-model="stxt">
</div>
</div>
heres the js file:
var app = angular.module("myApp", ['ngRoute']);
app.config(function($routeProvider) {
$routeProvider
.when('/angular', {
templateUrl: 'angular.php',
controller: 'dataCtr'
})
.when('/details', {
templateUrl: 'details.php',
controller: 'dataCtr'
})
.otherwise({
redirectTo: '/angular'
});
});
app.controller('dataCtr', function($scope ,$http ,$location ,$route ,$routeParams) {
$http({
method: "GET",
url: "json.php"})
.success(function (response) {$scope.names = response;});
$scope.changeView = function()
{
$location.url('/details');
};
$scope.disp = function(id)
{
$scope.stxt = $scope.names[id-1].Title;
};
});
The disp function is working fine on the angular view. But not being routed on the second view. I think the syntax for calling the two views in ng click is correct. OR if there any other method to call the associated table cell value to the second view. Please Help.
After a lots of research i figured it out.I used a factory service
app.factory('Scopes', function ($rootScope) {
var mem = {};
return {
store: function (key, value) {
$rootScope.$emit('scope.stored', key);
mem[key] = value;
},
get: function (key) {
return mem[key];
}
};
});
Added this to JS.
Because The scope gets lost on second Controller ,Services help us retain the scope value and use them in different controllers.Stored the scope from first controller
app.controller('dataCtr', function($scope ,$http ,$location,$rootScope,Scopes) {
Scopes.store('dataCtr', $scope);
//code
});
and loaded in the seconded controller.
app.controller('dataCtr2', function($scope ,$timeout,$rootScope,Scopes){
$scope.stxt = Scopes.get('dataCtr').disp;
});
Second view is not working because you cannot use $scope.$apply() method.
$apply() is used to execute an expression in angular from outside of the angular framework.$scope.$apply() right after you have changed the location Angular know that things have changed.
change following code part ,try again
$location.path('/detail');
$scope.$apply();

Angular js redirect URL on same page?

I am building an node js app within which I have one page on angular js. On one of the pages, all the users are listed down(as hyperlinks) and I click on one of them to access the information about that user.
So, if the first page's URL(i.e. all the users) is /users, I want the second URL to look like /users/:id. So, in a way I want to mimic the REST API format.
The user's info has been found and once the user-id has been found, I m trying to use $location.path(index).
Initially I thought using something like ng-if would help me in rendering using the same page. So, on my .jade file, I have added this condition:
div(ng-show='loadAllUsers()')
$scope.loadAllUsers = function(){
console.log($scope.index == -1)
return $scope.index == -1;
};
$scope.index has been initialized to -1. So, I thought something like this would work when a new id value has been generated. But, the problem is it doesn't seem to reload the whole page or div.. I tried using window.location.href as well. That, even though updated the URL but even that breaks...
So, is there a way on doing this on the same jade file by any chance? If not , then how exactly should I go about this problem?
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, UserService) {
$scope.userDetails={};
//get the list of users from data base. here i am taking some dummy values.
$scope.users=[{
id:1,
name:"Rahul"
},
{
id:2,
name:"Ajay"
},
{
id:3,
name:"Mohit"
}];
// get user details
$scope.getUserDetails=function(userId){
UserService.get({id:userId},function(userDetails){
$scope.userDetails=userDetails;
});
};
});
// No need to change the page URL. Above function will
// call 'UserService' factory. UserService will communicate
// with REST API with URL pattern 'app/rest/users/:id'.
// ':id' will be replaced by the id passed by above function.
// like 'app/rest/users/2'
angular.module('myApp').factory('UserService',function ($resource) {
return $resource('app/rest/users/:id', {}, {
get':{method:'GET', isArray: false}
});
});
<div ng-app="myApp" ng-controller="myCtrl">
<div>
<table>
<tr>
<th>Id</th>
<th>Name</th>
</tr>
<tr ng-repeat="user in users">
<td>{{user.id}}</td>
<td ng-click="getUserDetails(user.id)">{{user.name}}</td>
<tr>
</table>
</div>
<div>
<h3>User Details</h3>
id : userDetails.id <br/>
name : userDetails.name <br/>
// other details
</div>
</div>

ng-repeat ng-click when the click function has already been called earlier in the code

First off, I read the plethora of other questions and answers regarding ng-click, ng-repeat, and child and parent scopes (especially this excellent one.)
I think my problem is new.
I'm trying to call a function using ng-click within a table. The app allows for the sorting of Soundcloud likes. The problem is that when I try to call the ng click function using new data, it still tries to call the function using the old data. Let me explain better with the example:
Controller:
function TopListCtrl($scope, $http) {
$scope.sc_user = 'coolrivers';
$scope.getData = function(sc_user) {
var url = 'http://api.soundcloud.com/users/'+ $scope.sc_user +'/favorites.json?client_id=0553ef1b721e4783feda4f4fe6611d04&limit=200&linked_partitioning=1&callback=JSON_CALLBACK';
$http.jsonp(url).success(function(data) {
$scope.likes = data;
$scope.sortField = 'like.title';
$scope.reverse = true;
});
}
$scope.getData();
$scope.alertme = function(permalink) {
alert(permalink);
};
}
HTML
<div id="topelems">
<p id="nowsorting">Now sorting the Soundcloud likes of <input type=text ng-model="sc_user"><button class="btn-default" ng-click="getData(sc_user);">Sort</button></p>
<p id="search"><input ng-model="query" placeholder="Filter" type="text"/></p>
</div>
<table class="table table-hover table-striped">
<thead>
<tr>
<th>Song</th>
<th>Artist</th>
<th>Likes</th>
<th>Played</th>
<th>Tags</th>
</tr>
</thead>
<tr ng-repeat="like in likes.collection | filter:query | orderBy:sortField:reverse">
<td width="30%"><a href="{{ like.permalink_url }}">{{like.title}}</td>
(Trying to call it here) <td>{{like.user.username}}</td>
<td>{{like.favoritings_count}}</td>
<td>{{like.playback_count}}</td>
<td>{{like.tag_list}}</td>
</tr>
</table>
</div>
</body>
</html>
So I have that function getData. I use it to load the data in using the soundcloud api. I have a form at the top that uses getData to load a new user's Soundcloud data in. I also call the getData function in the controller so that there is an example on the page upon loading.
The problem is when I try to load a new user's data from a <td> I want to be able to click on the user to see and sort their likes.
How do I 'clear' the function or the global namespace (am I even refering to the right thing)? How can I reuse the getData function with a new variable?
Working Jsfiddle for this
In your getData function you have this line:
var url = 'http://api.soundcloud.com/users/'+ $scope.sc_user +'/favorites.json...
but you are passing in the variable sc_user to your getData function and should be using it like this (no $scope):
var url = 'http://api.soundcloud.com/users/'+ sc_user +'/favorites.json...
That being said... your initial data load fails because you are calling:
$scope.getData();
and not:
$scope.getData($scope.sc_user);

Resources