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.
Related
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.
I'm trying to use this AngularJS material chip.
(CONTACT CHIP - With auto-complete)
https://material.angularjs.org/latest/demo/chips
And it has a different structure of what I'm used to. I want to adapt to get the contacts from my mongodb with $http, like:
$http.get("/contacts").success(function(response) {
contacts = response;
});
But in their Angular Material code example is like this:
angular.module('MyApp',['ngMaterial', 'ngMessages', 'material.svgAssetsCache'])
.controller('ContactChipDemoCtrl', DemoCtrl);
function DemoCtrl ($q, $timeout) {
...
function loadContacts() {
var contacts = [
'Marina Augustine',
'Oddr Sarno',
'Nick Giannopoulos',
'Narayana Garner',
'Anita Gros',
'Megan Smith',
'Tsvetko Metzger',
'Hector Simek',
'Some-guy withalongalastaname'
];
}
...
How can I use $http as a parameter for the DemoCtrl function? To get the contacts from db
MyModule.controller("DemoController", DemoCtrl);
DemoCtrl.$inject = ['$http'];
function DemoCtrl ($http) {
$http.get("/contacts").success(function(response) {
contacts = response;
});
Above is the preferred way to setup a controller because it doesn't use an anonymous function rather than:
MyModule.controller("DemoController", ['$http', function($http) {
$http.get("/contacts").success(function(response) {
contacts = response;
}]);
You are assigning response data to variable contacts which has no angular scope context
If you are using $scope as your data model for view it would be
$http.get("/contacts").then(function(response) {
$scope.contacts = response.data;
});
Or if using controllerAs alias in view:
var vm = this
$http.get("/contacts").then(function(response) {
vm.contacts = response.data;
});
Also need to inject $http in controller
EDIT: Better phrasing of the question. I am basically looking at how to use the variable stored in $scope.item (grabbed from URL using $stateParams) to access the related object in the products JSON array.
Alright so I have used a combination of ui-router and ng-ref so that when you click a product on the "#/shop/" page it creates a URL "#/shop/productname" that when navigated to opens a blank div on the page that is meant to contain details about the product mentioned in the URL.
The issue I am having, and I'm sure there is something simple I am overlooking, is how to get the corresponding data based on the name in the URL? So that I can display product name/price etc that is stored in a JSON object?
Any help would help a ton! It's very possible I am going about this all wrong so please refer me in the right direction if you feel I could choose a better path.
HTML:
shop.html URL: #/shop
...
<a ng-repeat="item in businesses | filter:{cat: cat} | filter:query"
ng-class="{active: item.selected}"
ng-href="#/shop/{{item.link}}"
ng-click="selectedItem(item)">
...
</a>
<div ui-view></div>
...
product.html URL: #/shop/productName
<h1>item.name</h1>
<h2>item.price</h2>
App.js
angular.module('app', [
'ngAnimate',
'ui.router'
])
.config(function ($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise('/shop');
$stateProvider
.state('shop',{
url: '/shop',
templateUrl: 'templates/shop.html',
controller: 'starWarsCtrl'
})
.state('shop.item',{
url: '/:item',
templateUrl: 'templates/three-quarter-page.html',
controller: function($scope, $stateParams){
$scope.item = $stateParams.item;
}
})
;
})
.controller('appCtrl', function ($scope) {
$scope.products = [
{
"name": "Product 1",
"index":1,
"link":"product1",
"price":"TBD",
}
];
$scope.selectItem = function (selectedItem){
_($scope.products).each(function (item){
item.selected = false;
if (selectedItem === item){
selectedItem.selected = true;
}
})
};
}) /*End Controller*/
});
This will get the selected item for you, assuming you match by the name.
$scope.selectedItem = _.where($scope.products, {name: $scope.item});
I think, if I were you I would use angular service to share data between controllers
and this service will handle the data for me so when I change the product it will return the item object
angular.module('app').factory('productsService', function () {
self = this;
self.products = [{
"name": "Product 1",
"index":1,
"link":"product1",
"price":"TBD",
}];
this.findByLink = function(link){
// loop through your data
// returns what found or null
}
return {
products : this.products
findById : this.findById
}
});
and inject this service in each controller
.controller('appCtrl', function ($scope, productsService) {
$scope.products = productsService.products;
..........
and to anther one
.controller('productCtrl', function ($scope, productsService, $stateParams) {
$scope.item = productsService.findById($stateParams.link);
..........
I have a service which I would like to use across multiple controllers. The services is defined like this:
app.factory('Data', ['$http',
function($http) {
var Data = this;
var theProduct = {};
return {
product: function() {
return theProduct;
},
getProduct: function(ext_id) {
return $http.post('get_product', {
product_id: ext_id
}).success(function(data) {
theProduct = data;
});
}
}
}
]);
I have a form, that uses the ProductFormController to retrieve product data when it's submitted. That controller looks like this:
app.controller('ProductFormController', ['$scope', '$http', 'Data',
function($scope, $http, Data) {
/*
* Get a product and all of it's data from the server
*/
$scope.getProduct = function() {
Data.getProduct($scope.extProductId).success(function(data) {
console.log(data);
});
}
}
]);
Then, I have an AppController, which should display certain sections when a product object exists in the Data service.
<div class="row" id="productInfo" ng-show="product().id" ng-controller="AppController">/div>
Within AppController, I have this line:
$scope.product = Data.product;
I would like the productInfo div to show whenever a product object exists in the Data service, but it seems that the variable never gets updated. I've seen this question, but do not believe the accepted answer actually answers the question:
Angular: share asynchronous service data between controllers
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.