I'm very new to AngularJS, and Web Development in general. I would really appreciate some help regarding the actions for client-server interactions and $resource
Here is a small snippet of code from my program
.factory('commentFactory', ['$resource', 'baseURL', function($resource, baseURL) {
var commentFac = {};
comment.getComment= function() {
return $resource(baseURL + "comments/", null);
};
return commentFac;
}])
In the following controller, $scope.feedback elements are being changed with the ng-model directive in the webpage
.controller('FeedbackController', ['$scope', 'commentFactory', function($scope, commentFactory) {
$scope.feedback = {mychannel:"", firstName:"", lastName:"", agree:false, email:"" };
$scope.sendFeedback = function() {
commentFactory.getComment().save(
$scope.feedback, //What I want to send back to the server
function() { //Callback functions. No idea what to put here
},
function() {
}
);
}])
How will $scope.feedback be stored in the server? How would i be able to later access the comments when needed? I'm almost !00% certain my .save action is icorrect, but I can't seem to find online how I'm supposed to use it. What do I put in the callback functions?
I'm sorry that this is such a rookie questions, but this is honestly a little difficult to comprehend.
Edit: I changed the line
return $resource(baseURL + "comments/", null);
to
return $resource(baseURL + "comments/:id", null);
and it worked. I'm not sure why though. Would appreciate an explanation and answers to my above questions.
Thanks again
Related
So Im having a hard time trying to get my head wrapped around promises in angularJs. I have mixed around my code to try to do some brute force/reverse engineering understanding of it but nothing is coming out to any viable conclusion.
My Code:
Is is making a call back to get a list of repositories that I manage. These are just stored in the database as basic objects with an id and url.
Here is my view. It allows to me delete, view, and clear metadata in my database about these repos.
<div class="container" ng-controller="adminCtrl as vm">
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
<label class="control-label" >Repos:</label>
<div ng-repeat="repo in vm.repos">
<div class="clearfix">{{repo.URL}}<br>
<button class="btn btn-primary" ng-click='vm.listFiles(repo.URL)'>View Files</button>
<button class="btn btn-primary" ng-click='vm.clearFiles(repo.URL)'>Clear Files</button>
<button class="btn btn-primary" ng-click='vm.clearRepo(repo.URL)'>Delete Repo</button>
</div>
<br>
</div>
<label class="control-label" >Files:</label>
<div ng-repeat="file in vm.files">
<li>{{file.FullPath}}</li>
</div>
</div>
</div>
<!-- /.row -->
</div>
Here is my controller with some basic functions
(function (angular) {
'use strict';
var ngModule = angular.module('myApp.adminCtrl', []);
ngModule.controller('adminCtrl', function ($scope, $resource) {
//"Global Variables"
var File = $resource("/api/file/:repoUrl");
var Repo_del = $resource("/api/repo/:repoUrl");
var Repo = $resource("/api/repo");
var vm = this;
vm.files = [];
vm.repos = [];
vm.clearFiles = clearFiles;
vm.listFiles = listFiles;
vm.clearRepo = clearRepo;
init();
//Anything that needs to be instantiated on page load goes in the init
function init() {
listRepos();
}
function listRepos() {
vm.repos = Repo.query();
}
//Lists all files
function listFiles(url) {
vm.files = File.query({repoUrl: url});
}
function clearRepo(url) {
Repo_del.remove({repoUrl: url});
}
function clearFiles(url) {
File.remove({repoUrl: url});
}
});
}(window.angular));
Now this works fine and dandy. It brings back the repos and list them. I can delete, view, and remove with all the functions.
My issue came up with when I was trying to make a list item disappear on delete (instead of needing a page load). To do this I needed to find the index of the item being deleted in the array and remove it. I was gonna use some lodash to do this.Seemed simple enough. My problem is, my vm.repos array is not available within the controller.
For example. When I try to print out vm.repos with a console log within the listRepos function like so
function listRepos() {
vm.repos = Repo.query();
console.log(vm.repos);
}
I get nothing back from console.log. So this is telling me its not being assigned. Which to me is peculiar because the list is showing up in the ng-repeat on the view using vm.repos.
I have also ran into a problem when I am able to print out the array. It has TONS of promise information in it. For example if I put the console.log in the init() function I will get an array back that is jammed packed with information under a Resource object.
Im not sure how to go about and parse this down to be a manageable object. Looking at basic guides I have found some examples but nothing I can translate into my situation.
How do I properly handle api/resource promises?
Another problem im having is being able to mock out all of the api responses in my tests. This is my next feat. I do not care if it gets addressed here but I feel its stemming from the same problem.
Here is my only test I was able to write for this controller.
'use strict';
describe('adminCtrl', function () {
beforeEach(function () {
module('myApp.adminCtrl');
module('myApp');
});
describe('listRepos()', function () {
it('should return a json object representing a repository',
inject(function (_$httpBackend_, $rootScope, $controller) {
var scope = $rootScope.$new();
var mockBackend = _$httpBackend_;
var expectedResponse = {id: 12345, url: "https://github.com/myuser/myrepo.git"};
mockBackend.expectGET('/api/repo').respond([expectedResponse]);
var ctrl = $controller('adminCtrl', {$scope: scope});
mockBackend.flush();
expect(ctrl.repos.length).toEqual(1);
console.log(ctrl.repos[0]);
expect((angular.equals(ctrl.repos[0], expectedResponse)));
}));
});
});
Sorry if this is alot. Hopefully this isnt a repeated question.
EDIT to show what im trying now.
function clearRepo(url) {
$http.delete('/api/repo/', {params: {repoUrl: url}}).then(function (){
//DO THINGS
});
Express:
app.delete('/api/repo/:repoUrl', repoCtrl.clear);
repoCtrl.clear
module.exports.clear = function (req, res) {
var repoURL = req.params.repoUrl;
//console.log(repoURL);
Repo.remove({URL: repoURL}, function(err, results) {
if (err) {
console.log("ERR: " + err);
} else {
console.log('\n' + repoURL + ' repo deleted... \n');
}
});
Error im getting:
DELETE http://localhost:3000/api/repo/?repoUrl=https:%2F%2Fgithub.com%2Fuw34%2Fmyrepo.git 404 (Not Found)
First, the promise:
Used by $http
Allow chaining async request
Works like this :
var promise = $http.get('/api/values');
promise.then(function(response) {
$scope.displayData = response.data;
});
It is the new way to avoid simple callback (why avoid callback ?? check this CallbackHell :))
Nevertheless, callback can be complicated, hard to follow for debug and everyone prefer write sync code.
To simplify, Angular allow you to code something which look like sync code (but internally, it is async). To do it, $resource encapsulate a promise.
// this code return an empty array, then after received server respond, it will populate the empty array with data.
var values = VALUES.query();
// A simple version of it can be code like this
function simpleQuery() {
var arrayReference = [];
$http.get('api/values').then(function(response) {
// populate array reference with data received from server
angular.forEach(response.data, function(value) {
arrayReference.push(value);
});
// after the return, angular run a $digest
// which will display all newly received data thank to biding on your view
});
return arrayReference ;
}
By doing this, I return an empty array which will be populate on server response.
It is possible to get the promise from a $resource if you prefer :
var promise = Repo.query().$promise;
promise.then(function(response) {
$scope.displayData = response.data;
});
In 2020, you will probably use Async/Await instead $resource ;)
If you want more information, don't hesitate.
I don't get what I'm doing wrong, I am trying to globally store and pass data from one controller to another via a service. I stored the data in one controller and confirmed that it was stored at the beginning of my buildReportController. Then, when I click a button on my UI, it opens reportResultsController. However, issue is, I can store the data correctly in buildReportController via locationHistoryService.store() but when I go to reportResultsController and calllocationHistoryService.get(), thepreviousLocationvariable inlocationHistoryService` is empty as if the data was never set. Any ideas on how why or how I can "globally" store data and pass it between controllers? Below is my attempt. Thanks!
In reportView.js
angular.module('reportView', [])
.service('locationHistoryService', function(){
var previousLocation = "";
return {
store: function(location){
previousLocation = location;
},
get: function(){
return previousLocation;
}
};
});
In buildReport.js
angular.module('buildReport', ['reportView'])
.controller('buildReportController', ['$rootScope', 'locationHistoryService'], function($rootScope, locationHistoryService){
$rootScope.$on('$locationChangeSuccess', function(e, newLocation, oldLocation){
locationHistoryService.store(oldLocation);
console.log("Old location: ", oldLocation);
});
}
In reportResults.js
angular.module('reportResults', ['reportView'])
.controller('reportResultsController', ['$rootScope', 'locationHistoryService'], function($rootScope, locationHistoryService){
console.log("location : ", locationHistoryService.get());
}
The locationHistoryService.get() method in reportResults.js is called before it is set in buildReport.js.
It would be better if you announce when the previousLocation variable has been set.
In reportView.js
angular.module('reportView', [])
.service('locationHistoryService',['$rootScope'] ,function($rootScope){
var previousLocation = "";
return {
store: function(location){
previousLocation = location;
$rootScope.$broadcast('previous-location-set');
},
get: function(){
return previousLocation;
}
};
});
In reportResults.js
angular.module('reportResults', ['reportView'])
.controller('reportResultsController', ['$rootScope', 'locationHistoryService'], function($rootScope, locationHistoryService){
$rootScope.$on('previous-location-set', function(){
console.log("location : ", locationHistoryService.get());
});
}
Your webapp should have only one module which is automatically bootstrapped by angular, and other modules as dependencies. The syntax of writing service is incorrect. You wrote .service but returning object which .factory should return. Here is working example of your code http://codepen.io/Chyngyz/pen/NxbdpW?editors=101
Also you wrote the safe for minification syntax of controllers incorrect, the function block of controller should be the last item in the array.
I've created a simple logging service in Angular:
app.service('$userInteraction', [function() {
var userLog = "";
this.log = function (datetime, screen, logMessage) {
userLog.concat(datetime + "\t" + screen + " Screen\t" + logMessage + "\n");
}
this.getLog = function () {
return userLog;
}
this.clearLog = function () {
userLog = "";
}
}]);
And I use it in one of my controllers like so:
app.controller('myController', ['$scope', '$userInteraction', function($scope, $userInteraction) {
$userInteraction.log(Date(), 'Login', 'Some random message.');
}]);
But when I run my code I get the following error:
TypeError: $userInteraction.log is not a function
Though I could've sworn that it worked before. I'm fairly new to Angular so this might very well be a newbie mistake. Thanks in advance!
this question is old, but help someone... You code run on plunker, problably you have duplicate services name... Check all files angularjs and verify if exist another service with same name.
I had similar problem. Two services with same name and call did not have function called.
Hi guys im a newbie in AngularJS I have a problem calling multiples http.get. $scope.countries is getting values from cities. What happend?
How can calling multiple http.get?
$scope.getInfo = function(){
$scope.refreshing=true;
//cities
$http.get(baseUrl+'cities/GET_INFO/ALL').success(function(data) {
$scope.cities = data[0];
$scope.cities.signal = $scope.getSignal(data[0].status);
$scope.refreshing=false;
alert('city');
});
//countries
$http.get(baseUrl+'countries/GET_INFO/ALL').success(function(data) {
$scope.countries = data[0];
$scope.countries.signal = $scope.getSignal(data[0].status);
$scope.refreshing=false;
// alert('countries');
});
}
Also I tried with:
$scope.getInfo2 = function(){
$scope.refreshing=true;
alert ('start');
$scope.urlcities = $http.get(baseUrl+'cities/GET_INFO/ALL');
$scope.urlcountries = $http.get(baseUrl+'cities/GET_INFO/ALL');
$q.all([$scope.urlcities, $scope.urlcountries]).then(function(values) {
alert('finish');
$scope.refreshing=false;
});
}
But this code get an error.. Thanks so much for your help !
Carlos,
You may have a race condition with the AJAX calls. Try chaining them together using promises:
$scope.getInfo = function(){
$scope.refreshing=true;
//cities
$http.get(baseUrl+'cities/GET_INFO/ALL').then(function(data) {
$scope.cities = data[0];
$scope.cities.signal = $scope.getSignal(data[0].status);
$scope.refreshing=false;
alert('city');
return $http.get(baseUrl+'countries/GET_INFO/ALL');
}).then(function(data) {
// countries
$scope.countries = data[0];
$scope.countries.signal = $scope.getSignal(data[0].status);
$scope.refreshing=false;
// alert('countries');
});
};
To learn more, watch the screencast:
https://egghead.io/lessons/angularjs-chained-promises
You can also learn more about promises here:
https://docs.angularjs.org/api/ng/service/$q
NOTE:
It is a best practice to move your data preparation, business logic and calculations out of the controller and into a service. Consider revising your code to encapsulate your AJAX request (using the $http service) into a service and then inject that service into the controller that is being used to present the data to the view.
You need to make Syncronous calls.
And in Angular world it is achieved using $q or promise.
Good article on that http://haroldrv.com/2015/02/understanding-angularjs-q-service-and-promises/
Hope it helps..
I am badly stuck with this problem of passing data from one controller to other in angularJS. Before my code was: whenever I click on templateController's div, it would trigger setTemplate with the help of ng-click... Now my objective was to send templateController's selected data to ReplyController...
After reading forum posts here, i decided to create a service called 'selectionService', so that i can transmit data between 2 controllers...
//Defined Service
proApp.service('selectionService', function() {
var selected_template;
addTemplate = function(newObj) {
selected_template = newObj;
};
getTemplate = function(){
return selected_template;
};
});
//Controller 1... where templates are selected
proApp.controller('TemplateController',function($scope, selectionService)
{
$scope.templates = [
{template_name:"Template 1", template_text:"We apologize for the interruption."} ,
{template_name:"Template 2", template_text:"Thank you for contacting us."} ,
} ,
];
// on ng-click
$scope.setTemplate = function(tmp)
{
selectionService.addTemplate(tmp);
}
});
// Controller 2 ... supposed to catch the selected template.
proApp.controller('ReplyController', function($scope, selectionService)
{
$scope.template = selectionService.getTemplate();
});
So whenever i run this code, i started getting this error
Object [object Object] has no method addTemplate...
Again I tweeked the code where they were suggesting to use Squarebrackets and put $scope , servicename and then write function with same parameters.. I don't understand why I should do this? Event after doing some changes like
[ '$scope' , 'service' , function($scope, service){}] ,
I am still not able to figure out the solution to pass data from one controller to other using service.
Could you help? What am I missing? I am very new to angularJS way of doing stuff.
I think it's actually quite simple. You just need to add your methods to the service by using this.. Currently they are declared on window. Change your service declaration to use this...
proApp.service('selectionService', function() {
var selected_template;
this.addTemplate = function(newObj) {
selected_template = newObj;
};
this.getTemplate = function(){
return selected_template;
};
});
As for using the array notation for dependencies, it's a good practice but it's not required. It'll save you from headaches if you ever run your code through a minifier.