Posting data from a form using $http (REST) - javascript

I'm trying to use Angular for CRUD operations, but I'm having some trouble sending POST requests to the server.
Here's my controller:
angular.module('myModule').controller("ListingCtrl", function($scope, posts) {
$scope.addProject = function () {
if (!$scope.title || $scope.title === '') {
return;
}
posts.create({
title: $scope.title,
short_description: $scope.short_description
});
$scope.title = '';
$scope.short_description = '';
};
});
Here's my service:
angular.module('myModule', [])
.factory('posts', [
'$http',
function($http){
var o = {
posts: []
};
return o;
}]);
o.create = function(post) {
return $http.post('linktomyliveAPI', post).success(function(data){
o.posts.push(data);
});
};
And finally, here's the view:
<div ng-controller="ListingCtrl">
<form ng-submit="addProject()">
<input type="text" ng-model="title"></input>
<input type="text" ng-model="short_description"></input>
<button type="submit">Post</button>
</form>
I've been able to successful make GET requests, but for some reason, I can't figure out POST.
My API was built using Django Rest Framework, if that matters.
Thanks!

I think the way you have added create method is not proper, you have to add that method on factory object
Put the create method on an object returned from factory.
In your service
angular.module('myModule', [])
.factory('posts', ['$http',function($http){
var create = function(post) {
return $http.post('linktomyliveAPI', post).success(function(data){
o.posts.push(data);
});
};
var o = {
posts: [],
// expose create method on factory object
create: create
};
return o;
}]);
Hopefully these will solve your problem.

Fixed it.
I had to change some server-side settings in order to get this to work.

Related

Passing $scope variable from Controller to Service

Currently writing a prototype app in Ionic, pretty new to ionic and angular. I've written a small JSON API with about 25 objects in it, I've been able to display the list of them on a page we'll call "Library", I'm trying now to use those list items as links to an individual page for each item we will call a "Lesson". The variable $scope.lessonId is being set properly in the controller but being set as undefined in the service. Is it possible to achieve what I'm trying to, or am I just flat out doing this wrong?
.controller('LibraryLessonCtrl', function($scope, $stateParams, LessonService) {
$scope.lessonId = $stateParams.libraryId;
console.log($scope.lessonId);
LessonService.getLessonId()
.then(function(response){
$scope.lesson = response;
console.log($scope.lesson);
});
})
.service ('LessonService', function($http){
return { getLessonId: function() {
return $http.get('api/postsAPI.json')
.then(function (response, lessonId) {
console.log(lessonId);
for(i=0;i<response.data.length;i++){
if(response.data[i].post_id == lessonId){
return response.data[i];
}
}
});
}
};
})
You have to pass your $scope.lessonId variable to your service call if you like to use the value inside your service.
.controller('LibraryLessonCtrl', function($scope, $stateParams, LessonService) {
$scope.lessonId = $stateParams.libraryId;
console.log($scope.lessonId);
LessonService.getLessonId($scope.lessonId)
.then(function(response){
$scope.lesson = response;
console.log($scope.lesson);
});
}).service ('LessonService', function($http){
return { getLessonId: function(lessonId) {
return $http.get('api/postsAPI.json')
.then(function (response) {
console.log(lessonId);
for(i=0;i<response.data.length;i++){
if(response.data[i].post_id == lessonId){
return response.data[i];
}
}
});
}
};
})
You could do it by passing Id to service and storing it there. Please try not to pass $scope variable to service as it is not a good practice. You can do following:
.service ('LessonService', function($http){
var lessionId;
return {
/*other methods*/
setLessionId: function(id) {
lessionId = id;
},
getLessionId: function(){
return lessionId;
}
};
})

AngularJS App: Load data from JSON once and use it in several controllers

I'm working on a mobile app using AngularJS as a framework, currently I have a structure similar to this:
app.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/', {
templateUrl : 'pages/home.html',
controller : 'homeCtrl'
})
.when('/one', {
templateUrl : 'pages/one.html',
controller : 'oneCtrl'
})
.when('/two', {
templateUrl : 'pages/two.html',
controller : 'twoCtrl'
});
}]);
app.controller('homeCtrl', ['$scope', function($scope) {
}]);
app.controller('oneCtrl', ['$scope', function($scope) {
}]);
app.controller('twoCtrl', ['$scope', function($scope) {
}]);
And then I'm displaying the content with an ng-view:
<div class="ng-view></div>
Things are working well but I need to load data from a JSON file to populate all the content of the app. What I want is to make and an AJAX call only once and then pass the data through all my different controllers. In my first attempt, I thought to create a Service with an $http.get() inside of it and include that in every controller, but it does not work because it makes a different ajax request everytime I inject and use the service. Since I'm new using angular I'm wondering what is the best way or the more "angular way" to achieve this without messing it up.
Edit: I'm adding the code of the service, which is just a simple $http.get request:
app.service('Data', ['$http', function($http) {
this.get = function() {
$http.get('data.json')
.success(function(result) {
return result;
})
}
});
Initialize the promise once, and return a reference to it:
No need to initialize another promise. $http returns one.
Just tack a .then() call on your promise to modify the result
angular.module('app', [])
.service('service', function($http){
this.promise = null;
function makeRequest() {
return $http.get('http://jsonplaceholder.typicode.com/posts/1')
.then(function(resp){
return resp.data;
});
}
this.getPromise = function(update){
if (update || !this.promise) {
this.promise = makeRequest();
}
return this.promise;
}
})
Codepen example
Edit: you may consider using $http cache instead. It can achieve the same results. From the docs:
If multiple identical requests are made using the same cache, which is not yet populated, one request will be made to the server and remaining requests will return the same response.
Try this to get JSON Data from a GET Link:
(function (app) {
'use strict';
app.factory('myService', MyService);
MyService.$inject = ['$q', '$http'];
function MyService($q, $http) {
var data;
var service = {
getData: getData
};
return service;
//////////////////////////////////////
function getData(refresh) {
if (refresh || !data) {
return $http.get('your_source').then(function(data){
this.data = data;
return data;
})
}
else {
var deferrer = $q.defer();
deferrer.resolve(data);
return deferrer.promise;
}
}
}
}(angular.module('app')));
Now you can add this dependency in your controller file and use:
myService.getData().then(function(data){
//use data here
}, function(err){
//Handle error here
});

angular how to set services in my case

I am trying to set http request data in one controller and let the data be used in multiple controller. I have something like
My services
angular.module('myApp').service('testService', ['Product','$q',
function(Product, $q) {
var products, targetProduct;
var deferred = $q.defer();
Product.query({
Id: 123
}, function(products) {
targetProduct = products[0];
deferred.resolve(products);
})
var getTargetProduct = function() {
var deferredtwo = $q.defer();
// return deferredtwo.promise;
deferred.promise.then(function(){
deferredtwo.resolve(targetProduct);
})
return deferredtwo.promise;
}
var setTargetProduct = function(targetProduct) {
targetProduct = targetProduct
}
return {
setTargetProduct: setTargetProduct,
getTargetProduct: getTargetProduct,
productPromise : deferred.promise
};
}
]);
nav controller
testService.productPromise.then(function(products){
$scope.products= products;
$scope.targetProduct = products[0];
})
//when user click the project ng-click = setTargetProduct(product);
$scope.setTargetProduct = function(targetProduct) {
testService.setTargetProduct(targetProduct)
}
product detail controller
testService.getTargetProduct().then(function(targetProduct) {
// works when page first loads
// but I don't know how to update the targetProduct when user select different
//targetProduct which means they trigger setTargetProduct() method
$scope.targetProduct = targetProduct;
})
As I stated above, I am not sure how to update the targetProduct in product detail controller when user pick another targetProduct. Can anyone help me about this? Thanks a lot!
As a matter of style, the function getTargetProduct doesn't need all this boilerplate code with promises. You want to return a simple promise wrapping your local data targetProduct. The function can be much cleaner :
var getTargetProduct = function() {
return $q.when(targetProduct);
}
Note: In the following, for convenience purpose, I will refer to your service testService by the name productService, and I will refer to your controller navController by the name ProductController
The controller NavController (gets the products as follows :
productService.getProducts().then(function(products) {
$scope.products = products;
}
When the user sets a target product (unchanged) :
$scope.setTargetProduct = function(targetProduct) {
testService.setTargetProduct(targetProduct)
}
Solution 1: nested controllers
If ProductDetailController is a nested controller of ProductController, the data targetProduct is shared without any logic from your part.
Solution 2: controllers not linked by a parent-child relationship
If the two controllers are not linked by a parent-child relationship, you can use $broadcast for broadcasting an updateTargetProduct event, and $on for handling that event.
In the controller from which we set the target product, we will find :
$rootScope.$broadcast('updateTargetProduct', targetProduct);
Note : $broadcast will broadcast the event from the rootscope down to the child scopes.
And in ProductDetailController, we will listen for this event :
$scope.$on('updateTargetProduct', function(event, data) {
// play with the received data
}
maybe your situation is not same as like me , but i made a service for my own $http call
var myService = angular.module('apix',[]);
myService.service('api',function( $http ){
this.http = function( method , path , data ){
return $http({
method: method,
url: path,
headers: {
'Content-Type' : 'application/x-www-form-urlencoded'
},
data : jQuery.param(data)
});
}
});
and used to call this as like
api.http('POST','your_path', data).success(function(result){ });
angular.module('myApp', [])
.factory('ipFactory', ['$http',
function($http) {
var service = {
getIp: function() {
return $http.get('http://ip.jsontest.com/', {
cache: true
})
.then(function(data) {
return data.data.ip;
});
}
}
return service;
}
])
.controller('ControllerOne', ['$scope', 'ipFactory',
function($scope, ipFactory) {
ipFactory.getIp()
.then(function(ip) {
$scope.ipAddress = ip;
});
}
])
.controller('ControllerTwo', ['$scope', 'ipFactory',
function($scope, ipFactory) {
ipFactory.getIp()
.then(function(ip) {
$scope.ipAddress = ip;
});
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="ControllerOne">
{{ipAddress}}
</div>
<div ng-controller="ControllerTwo">
{{ipAddress}}
</div>
</body>

update scopes in multiple controllers after $http

I'm struggling to figure out how to do this. Hope anyone can help :)
I have multiple controllers in my Angular app. Like titleCtrl and SettingsCtrl
I have a service which holds a variable like this:
var myVar = {title: 'test', settings: {color: 'black', font: 'verdana'}};
I'm making a $http.get request to update the "myVar" variable from the server.
The question is, how do I update the $scope.title in titleCtrl and $scope.settings in SettingsCtrl AFTER the http request has finished? I know how to do it in a single controller, but how do I update the $scopes in multiple controllers?
Use a watch on that variable in the service. When its updated, then update your values in controller scope. Here's an example:
Inside your controller, you can watch a var myVar on YourService and when it changes, update a variable called myVarInController with the value it changed to.
$scope.$watch(
// This function returns the value being watched.
function() {
return YourService.myVar;
},
// This is the change listener, called when the value returned above changes
function(newValue, oldValue) {
if ( newValue !== oldValue ) {
$scope.myVarInController = newValue;
}
}
);
Just in you service create a object when you get data from you server copy it to that object, so all your controllers can reference to that object.
Please see here http://plnkr.co/edit/j25GJLTHlzTEVS8HNqcA?p=preview
JS:
var app = angular.module('plunker', []);
app.service('dataSer', function($http) {
var obj = {};
getData = function() {
$http.get("test.json").then(function(response) {
angular.copy(response.data, obj);
});
}
return {
obj: obj,
getData: getData
};
});
app.controller('MainCtrl', function($scope, dataSer) {
$scope.data = dataSer;
$scope.get = function() {
$scope.data.getData()
}
});
app.controller('SecondCtrl', function($scope, dataSer) {
$scope.data = dataSer;
});
HTML:
<div ng-controller="MainCtrl">
<button ng-click="get()">get data</button>
<p>Fist Controller:
<br/>{{ data.obj.title}}</p>
</div>
<div ng-controller="SecondCtrl">
<p>Second Controller:
<br/>{{data.obj.settings}}</p>
</div>
Use both factory and service to pass value to two controllers. This is the only way to pass value
angular.module('mulipleCtrlApp', [])
.service('shareService', function () {
return {
title: 'test',
settings: {
color: 'black',
font: 'verdana'
}
};
})
.controller('titleCtrl', function ($scope, shareService) {
$scope.myVar = shareService;
$scope.testchange = function () {
$scope.myVar.title = 'Completed test';
};
})
.controller('settingCtrl', function ($scope, shareService) {
$scope.myVar = shareService;
});
Egghead Link
Jsfiddler Link example
Make your service return promise object.
Then in controller you can define a success call back to fetch title in one and settings in
another controller once the promise is resolved.
Code to use promises
In your service class:
var factory = {};
var factory.fetchData = function () {
return $http({method: 'GET', url: '/someUrl'});
}
return factory;
In controller 1:
$scope.getData = function(){
factory.fetchData().success(response){
$scope.title = response.title;
}
}
Similarly you can update controller 2, to set settings data.
I've found a better and easier maintainable solution in my opinion. Simply do the following to achieve to-way data-binding between one (or more) controller(s) with a service:
Lets assume you fetch (i.e. $http) and store data in your service (serviceName) in the variable serviceData.
In your controller reference the service like this to achieve to-way data-binding:
$scope.data = serviceName
In your view/html bind to the data properties like this:
<input ng-model="data.serviceData.title">
Thats it! :) When your serviceData variable updates the view/scope does as well. This will work with multiple controllers.

How to get every object in an JSON array in Angular

I'm new in AngularJS, and JS overall. But I think it's fairly simple coming from Java in school.
My first service contained this:
app.factory('User', function($http) {
var user = {
username : null,
company : null,
address : null,
city: null,
country: null
};
$http.get('/webservice/user').success(function(data){
user.username = data.username;
user.company = data.company;
user.address = data.address;
user.city = data.city;
user.country = data.country;
})
return user;
})
I accessed it from the UserCtrl:
app.controller('UserCtrl', ['$scope', 'User', function ($scope, User){
$scope.user = User;
}]);
And in the index.html I simply called:
{{user.username}} {{user.company}} ...
And so forth.
Now I have an array of objects, I use this method:
app.factory('Cards', function($http) {
var cards = [{id:null, name: null, info: null}];
$http.get('/webservice/cards').success(function(data){
for(var i=0;i<data.length;i++){
cards[i] = data[i];
}
})
return cards;
})
The controller looks the same.
app.controller('SearchCtrl', ['$scope', 'Cards', function ($scope, Cards){
$scope.cards = Cards;
}]);
And I access them with a
<li ng-repeat="card in cards">
{{card.id}} {{card.info}}</li>
My question is, do I really have to have a for loop in the $http.get() method?
No Need for the loop, angular js ng-repeat itself works as an foreach loop.
// Js Code
app.factory('Cards', function($http) {
$scope.cards = [];
$http.get('/webservice/cards').success(function(data){
$scope.cards = data;
}
return $scope.cards;
})
//html
<li ng-repeat="card in cards">
{{card.id}} {{card.info}}</li>
I solved this by using ngResource.
When doing using RESTful APIs this is the way to do it. Instead of using the $http.get() method, I simply used
app.factory('CardService', ['$resource', function($resource) {
return $resource('/webservice/cards',{});
}]);
Using $scope inside of a service is not recommended, that way you have lost the functionality of the service.
In the controller, I then used:
app.controller("CardCtrl", ['$scope', 'CardService', function($scope, CardService){
$scope.cards = CardService.query();
})
Using the other ways caused conflict in the 2-way-binding. First it launched the controller, then checked the service, then the controller, then the service again. When working with an object, this worked great. Working with an array, this way is better.

Categories

Resources