Directives angular - javascript

i'm really new on angular.
Im using angular 1.6, and i need to do some changes on a existing app.
As i could search, the previous developer was using http://www.codingdrama.com/bootstrap-markdown/ to have a textarea with some text options and a preview. My task now is to override the preview button to call our API with the text inserted and API return some result. On docs of that markdown I added up I found this.
onPreview: function(e) {
var previewContent
if (e.isDirty()) {
var originalContent = e.getContent()
previewContent = "Prepended text here..."
+ "\n"
+ originalContent
+ "\n"
+"Apended text here..."
} else {
previewContent = "Default content"
}
return previewContent
},
So i started to override that:
app.directive("markdowntextarea", ['$http', function ($http) {
return {
link: function (el_scope, element, attr) {
var previewContent = "preview";
element.markdown(
{
autofocus: false,
savable: false,
onPreview: function (e) {
console.log('1');
if (e.isDirty()) {
console.log('2!!')
var originalContent = e.getContent();
$http({
url: '/api/markdown/',
data: {"body": originalContent, "actual_format": "md", "desire_format": "html"},
method: 'POST'
}).then(function successCallback(response) {
console.log(response.data.content);
previewContent = response.data.content;
});
}else{
console.log('3')
previewContent = "";
}
previewContent = 'test';
return previewContent;
},
});
}
}
}]);
I can't find the error I have, but the previewContent always return "preview". From API side is ok, and the response.data.content is also correct.
Have no idea what to do next

The challenge is that you execute an asynchronous function and want to return it's value. In your code example you already returned from the onPreview function while the async function is still executed in the background. In AngularJS you can use promises to solve this kind of problem: "A service that helps you run functions asynchronously, and use their return values (or exceptions) when they are done processing".
BUT: As far I can see from the source the markdown component does not support promises. The onPreview method expects a string to be returned. The only option is to wait inside onPreview until the AJAX request returns - which is strongly discouraged. So IMHO it is not possible to use an AJAX request inside of onPreview.
IF the bootstrap-markdown would support promises you could try this:
app.directive("markdowntextarea", ['$http', '$q', function ($http, $q) { // inject $q
...
onPreview: function (e) {
console.log('im here!!');
var deferred = $q.defer();
if (e.isDirty()) {
var originalContent = e.getContent();
$http({
url: '/api/markdown/',
data: {"body": originalContent, "code": "a"},
method: 'POST'
}).then(function successCallback(response) {
console.log("successCallback", response.data.content);
deferred.resolve(response.data.content);
}, function errorCallback(response) {
console.log("errorCallback");
deferred.reject("error");
});
} else {
// quando esta vazio
deferred.resolve("");
}
return deferred.promise;
},
...
Here is a JSFiddle that demonstrates the concept. It's an update of Dave Kerr's AngularJS Promises - The Definitive Guide Part 2 - JSFiddle to AngularJS 1.6.

Related

How to wait for promise to complete with returned value using angularjs

I’m having an issue with my project. In my angularjs controller a function is being executed and then my function to make a call to my database to update a record is executing without waiting for the first function to complete and therefore sending over an undefined result variable.
Below you can find my code snippets with my attempts so far.
Submit button function:
$scope.submitNewStarters = function () {
// result is returning as undefined <<<<< Issue
var result = $scope.sendNewStarterDetailsToApi();
$scope.updateArchivedImportFlag(result);
};
Controller function handling the logic:
$scope.sendNewStarterDetailsToApi = function () {
swal({
title: "Confirmation",
text: "Are you sure you want to import the new starter details?",
icon: "info",
dangerMode: true,
buttons: ["No", "Yes"]
}).then(function (approve) {
if (approve) {
// Get each of the new starter details that have been set to true for import.
var newStartsToImport = $scope.tableParams.data.filter(x => x.imported == true);
for (let i = 0; i < newStartsToImport.length; i++) {
// Parses the current new starter object into a stringified object to be sent to the api.
$scope.newStartsToImport = $scope.createApiObject(newStartsToImport[i]);
// A check to ensure that nothing has went wrong and that the stringify object has worked.
if ($scope.newStartsToImport !== "") {
apiFactory.postNewStarterDetailsToApi($scope.newStartsToImport).then(function (response) {
var isSuccessful = response.data.d.WasSuccessful;
if (isSuccessful)
toastr.success("New starter details successfully sent to API.", "Success!");
else {
var errorMessage = response.data.d.ErrorMessage;
toastr.error("New starter details were unsuccessfully sent to API. Please try again. \n" + errorMessage, "Error!");
}
});
}
else {
toastr("An error has occurred when attempting to create the data object to be sent to API. The process has stopped!", "Error!");
break;
}
}
return newStartsToImport;
}
else
toastr.info("No new starter details were sent to API", "Information!");
});
};
Factory function for API call:
postNewStarterDetailsToApi: function (data) {
return $http({
url: "https://www.example.com/services/service.svc/Import",
method: "POST",
data: data,
headers: {
'Content-Type': 'application/json; charset=utf-8',
}
}).then(function successCallbwack(response) {
// this callback will be called asynchronously
// when the response is available
return response;
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
console.log('An error has occured during the function call postNewStarterDetailsToApi(): ', response);
});
}
So with the concept of promises how am I able to execute the sendNewStarterDetailsToApi function, wait for it to complete and then return the populated array? Once the populated array (result) is returned then execute the updateArchivedImportFlag function.
Below I've added an illustration of what I'd like to achieve:
The approach I am using is , save all the promises in an array .
Use any promise library or es6 Promise, and use .all function to wait for all promises to execute
The syntax i wrote is not totally correct. Since you are using angular js , you can use $q.all
$scope.sendNewStarterDetailsToApi = function () {
swal({
title: "Confirmation",
text: "Are you sure you want to import the new starter details?",
icon: "info",
dangerMode: true,
buttons: ["No", "Yes"]
}).then(function (approve) {
var res = [];
if (approve) {
// Get each of the new starter details that have been set to true for import.
var newStartsToImport = $scope.tableParams.data.filter(x => x.imported == true);
for (let i = 0; i < newStartsToImport.length; i++) {
// Parses the current new starter object into a stringified object to be sent to the api.
$scope.newStartsToImport = $scope.createApiObject(newStartsToImport[i]);
// A check to ensure that nothing has went wrong and that the stringify object has worked.
if ($scope.newStartsToImport !== "") {
res.push(apiFactory.postNewStarterDetailsToApi($scope.newStartsToImport))
}
else {
toastr("An error has occurred when attempting to create the data object to be sent to API. The process has stopped!", "Error!");
break;
}
}
return Promise.all(res);
}
else
toastr.info("No new starter details were sent to API", "Information!");
}).then(function (data) {
data.forEach((response) => {
var isSuccessful = response.data.d.WasSuccessful;
if (isSuccessful)
toastr.success("New starter details successfully sent to API.", "Success!");
else {
var errorMessage = response.data.d.ErrorMessage;
toastr.error("New starter details were unsuccessfully sent to API. Please try again. \n" + errorMessage, "Error!");
}
})
}).then((res) => {
//call Submit new starters
})
};

Angularjs factory inject is not working

I am developing a web application in Angularjs. I am making some API calls using $http service. I am using factories to call $http services. I have below controller.
(function () {
angular.module('RoslpApp').controller('SavedVechilces', ['$scope','DeleteVechicle', function ($scope,DeleteVechicle)
$scope.deletesavedCar = function (sref) {
DeleteVechicle.deleteCar(sref.CarID).success(function (resposne) { console.log(resposne) }.error(function (error) { console.log(error)}))
}
}]);
})();
RoslpApp.factory("DeleteVechicle", ['$http', '$cookieStore','cfg', function ($http, $cookieStore,cfg) {
var factoryObject = {};
var baseurl = cfg.Baseurl;
var LoginID = $cookieStore.get("LoginID");
var cookiePreferredLanguage = $cookieStore.get('PreferredLanguage');
var urlapi = baseurl + "api/Vehicle/DeleteSavedVehicle";
factoryObject.deleteCar = function (carID) {
var request = {
url: urlapi,
method: 'POST',
data: {
LoginID: LoginID,
CarID: carID
},
headers: {
RequestedPlatform: "Web",
RequestedLanguage: cookiePreferredLanguage
},
};
return $http(request);
}
return factoryObject;
}
]);
When I run above code I will get Unknown provider: DeleteVechicleProvider <- DeleteVechicle <- SavedVechilce error. I injected DeleteVechicle in my controller. May I know the way I am CarID to the factory and returning response is the correct way? Any help would be appreciated. Thank you.
There are two issues, you need to change your controller/factory as,
RoslpApp.controller
also the request should be,
DeleteVechicle.deleteCar(sref.CarID).then(function(response){
console.log(resposne)
},function(error){
console.log(error)
});

AngularJs calling multiple service function : which is the best way to call multiple REST service on angularjs during the init step?

I have this infrastructure
[play] <-REST-> [karaf]
and this controller
$scope.getPrototypes = function (node) {
connectHttpService.getPrototypes(function (response) {
$scope.prototypes = response;
}, node);
}
$scope.getCommandsWithAck = function (node) {
connectHttpService.getCommands(function (response) {
$scope.commandsWithAck = response;
}, node, true);
}
$scope.getCommandsWithoutAck = function (node) {
connectHttpService.getCommands(function (response) {
$scope.commandsWithoutAck = response;
}, node, false);
}
where connectHttpService is the service
function getCommands(successHandler, failHandler, nodeId, ack) {
$http({
method: 'GET',
........MY ENDPOINT.........
}
}).success(function(response) {
successHandler(response);
}).error(function(response) {
console.log("connectHttpService got an error response: " + JSON.stringify(response));
})
}
the problem is my init method (called thorugh ng-init) is
$scope.initCommands = function () {
$scope.currentNode = $stateParams.node;
$scope.getPrototypes($scope.currentNode); //(1)
$scope.getCommandsWithAck($scope.currentNode); //(2)
$scope.getCommandsWithoutAck($scope.currentNode); //(3)
}
}
the $scope.getCommandsWithoutAck is called but doesn't return. On the server side (karaf) I see the call and the response. No error on the browser.
if I remove (1) or (2) it works
if I change the position of (3) and (2) it works, but only since (2) doesn't return nothing.
In other words: which is the best way to call multiple REST service on angularjs during the init step?
Try to use $q
Like this
$scope.currentNode = $stateParams.node;
$q.all([
$scope.getPrototypes($scope.currentNode), //(1)
$scope.getCommandsWithAck($scope.currentNode), //(2)
$scope.getCommandsWithoutAck($scope.currentNode) //(3)
]).then(function(result){
console.log(result[0]);//(1)
console.log(result[1]);//(2)
console.log(result[2]);//(3)
});
And you have to return promise from service
Like this
$scope.getCommandsWithAck = function (node) {
return connectHttpService.getCommands(function (response) {
$scope.commandsWithAck = response.data;
return $scope.commandsWithAck; //to complete promise
}, node, true);
}
N:B: you have to inject $q in your controller

displaying Data from multiple tables with AngularJs

I have been reading different posts with similar questions but I cannot get this figured out. I have a Job class that is linked to different tables such as Customer and Employee. The Data is coming back from the Database but I cannot get the Angular Table to display the linked classes. The suggestions have been to use different mods, restangular, angular-activerecord, ModelCore and this method
angular js model relationships
I am not sure the best route to take and what would be the simplest way of doing it.
app.factory('Job', function ($resource) {
return $resource('/api/apiJob/:id',
{ id: '#id' },
{ 'save': { method: 'POST' } },
{ 'update': { method: 'PUT' } },
{ 'query': { method: 'GET', isArray: false } });
});
app.factory('jobFactory', function ($http) {
return {
updateJob: function (job) {
return $http.put('/api/apiJob/' + job.JobId, job);
}
};
});
app.factory('Customer', function ($resource) {
return $resource('/api/apiCustomer/:id',
{ id: '#id' },
{ 'save': { method: 'POST' } },
{ 'update': { method: 'PUT' } },
{ 'query': { method: 'GET', isArray: false } });
});
app.factory('customerFactory', function ($http) {
return {
updateCustomer: function (customer) {
return $http.put('/api/apiCustomer/' + customer.CustomerId, customer);
}
};
});
'use strict';
app.controller('JobCtrl', function ($scope, Job, $resource, $route, jobFactory, notificationFactory, $http) {
////GET Jobs
$scope.jobArray = Job.query()
//New Job Modal
$scope.NewJobModal = function () {
$('#NewJobModal').modal();
}
$scope.submitJob = function () {
var data = {
JobId: $scope.JobId,
JobNumber: $scope.JobNumber,
JobName: $scope.JobName,
CustomerName: $scope.CustomerName,
JobDescription: $scope.JobDescription,
OriginalContract: $scope.OriginalContract,
BillingDate: $scope.BillingDate,
}
$http.post('/api/apiJob/PostNewJob', data).success(function (data, status, headers) {
console.log(data);
});
window.top.location.reload();
};
//End New Job Post
//Delete Job
$scope.deleteJob = function (job) {
Job.delete({ id: job.JobId }, function () {
if ($scope.jobArray.length === 1) {
$scope.jobArray.splice(-1, 2);
} else {
$scope.jobArray.splice(job.JobId - 1, 2);
}
window.top.location.reload();
});
};
//End Delete Job
$scope.updateJob = function (job) {
jobFactory.updateJob(job).success(successCallback).error(errorCallback);
};
$scope.job = [];
var successCallback = function (data, status, headers, config) {
notificationFactory.success();
return $('#editJobModal').modal('hide');
};
var errorCallback = function (data, status, headers, config) {
notificationFactory.error(data.ExceptionMessage);
};
//End Edit Job
}); //End Job Controller
What It looks like in the Browser Console
0: {$id:1, JobId:1, JobNumber:2534, JobName:St.Lukes, JobDescription:Rebuilding Cafeteria,…}
$id: "1"
BalanceDue: 89654123
BalanceToBill: 541256
BillingDate: "2014-08-12T14:43:22.507"
BillingForm: "Invoice"
Budget: 854523658
CertPayroll: true
ChangeOrders: [{$id:4, ChangeOrderId:1, ChangeOrderNumber:7854, ChangeOrderDate:2014-08-12T14:43:22.673,…}]
ContractDate: "2014-08-12T14:43:22.507"
Customers: [{$id:2, CustomerId:2, CustomerName:Grove at Wilcrest, CustomerPhoneNumber:8327899667,…}]
0: {$id:2, CustomerId:2, CustomerName:Grove at Wilcrest, CustomerPhoneNumber:8327899667,…}
Employees: [{$id:3, EmployeeId:2, AccountName:Ham Sandwich, EmployeeFirstName:Scott, EmployeeLastName:Willis,…}]
JobAddress: "1234 Mason Rd"
JobCity: "Katy"
JobCost: 784556124
Updated Factory
app.factory('JobGet', function ($http, $q) {
var data = $http({
method: 'GET',
url: '/api/apiJob'
})
return {
query: function () {
var deferred = $q.defer();
setTimeout(function () {
deferred.resolve(data)
}, 2000);
return deferred.promise;
}
};
});
Network Response Tab
[{"$id":"1","JobId":1,"JobNumber":2534,"JobName":"St.Lukes","JobDescription":"Rebuilding Cafeteria","OriginalContract":1250210,"ContractDate":"2014-08-12T14:43:22.507","BillingDate":"2014-08-12T14:43:22.507","TotalCO":12502105,"RevisedContract":452136852,"Budget":854523658,"BillingForm":"Invoice","TESPM":"Frank Harvel","TESSuperintendent":"Rudy Sanchez","Status":"Active","MoreShit":"More shit goes here","TaxExempt":true,"CertPayroll":true,"JobCost":784556124,"RemainingBudget":96523145,"Profit":854125,"Percentage":45,"TotalBilled":45236554,"BalanceToBill":541256,"PaidToDate":0,"BalanceDue":89654123,"JobAddress":"1234 Mason Rd","JobCity":"Katy","JobState":"TX","JobZipcode":77493,"JobCounty":"Harris","JobPhone":2814569654,"JobFax":2814563251,"JobHidden":false,"Customers":[{"$id":"2","CustomerId":2,"CustomerName":"Grove at Wilcrest","CustomerPhoneNumber":8327899667,"CustomerFaxNumber":7134568547,"CustomerAddress":"56328 Richmond Ave","CustomerCity":"Houston","CustomerState":"TX","CustomerZipcode":77042,"CustomerWebsite":"grovewilcrest.com","CustomerOtherShit":"Other Shit Goes here","CustomerHidden":false,"CustomerPM":null,"CustomerAdmin":"Jane Miller","CustomerAccountant":"Betsy Sue","TESSuperintendent":null,"JobId":1,"Job":{"$ref":"1"}}],"Employees":[{"$id":"3","EmployeeId":2,"AccountName":"Ham Sandwich","EmployeeFirstName":"Scott","EmployeeLastName":"Willis","EmployeeTitle":"Admin","EmployeeCellPhone":2818567854,"EmployeeOfficePhone":7134527854,"EmployeeEmail":"testing#gmail.com","CompanyEmployeeId":12521,"EmployeeHidden":false,"EmployeeIsSuper":true,"EmployeeIsPM":true,"JobId":1,"Job":{"$ref":"1"}}],"ChangeOrders":[{"$id":"4","ChangeOrderId":1,"ChangeOrderNumber":7854,"ChangeOrderDate":"2014-08-12T14:43:22.673","ChangeOrderName":"Insert Name Here","ChangeOrderDescription":"It changed","ChangeOrderAmount":4000,"ChangeOrderApprovedDate":"2014-08-12T14:43:22.673","ChangeOrderApprovedAmount":3000,"ChangeOrderApprovedNumber":1,"ChangeOrderAttn":"Frank Harvel","ChangeOrderHidden":false,"JobId":1,"Job":{"$ref":"1"}}]},{"$id":"5","JobId":2,"JobNumber":12343,"JobName":"Katy Mills","JobDescription":"New Mall Bathrooms","OriginalContract":32623212,"ContractDate":"2014-08-12T14:43:22.507","BillingDate":"2014-08-12T14:43:22.507","TotalCO":12502105,"RevisedContract":452136852,"Budget":854523658,"BillingForm":"Invoice","TESPM":"Frank Harvel","TESSuperintendent":"Mike Hall","Status":"Active","MoreShit":"More shit goes here","TaxExempt":true,"CertPayroll":true,"JobCost":784556124,"RemainingBudget":96523145,"Profit":854125,"Percentage":45,"TotalBilled":45236554,"BalanceToBill":541256,"PaidToDate":0,"BalanceDue":89654123,"JobAddress":"1234 Mason Rd","JobCity":"Katy","JobState":"TX","JobZipcode":77493,"JobCounty":"Harris","JobPhone":2814456965,"JobFax":2814563225,"JobHidden":false,"Customers":[{"$id":"6","CustomerId":1,"CustomerName":"City Center","CustomerPhoneNumber":8327899667,"CustomerFaxNumber":7134568547,"CustomerAddress":"123453 HWY 6","CustomerCity":"Katy","CustomerState":"TX","CustomerZipcode":77493,"CustomerWebsite":"citycenter.com","CustomerOtherShit":"Other Shit Goes here","CustomerHidden":false,"CustomerPM":null,"CustomerAdmin":"Jane Miller","CustomerAccountant":"Betsy Sue","TESSuperintendent":null,"JobId":2,"Job":{"$ref":"5"}}],"Employees":[{"$id":"7","EmployeeId":3,"AccountName":"Ice Cream","EmployeeFirstName":"Aaron","EmployeeLastName":"Horstmann","EmployeeTitle":"Office Bitch","EmployeeCellPhone":2818567854,"EmployeeOfficePhone":7134527854,"EmployeeEmail":"aaron#gmail.com","CompanyEmployeeId":12521,"EmployeeHidden":false,"EmployeeIsSuper":true,"EmployeeIsPM":true,"JobId":2,"Job":{"$ref":"5"}}],"ChangeOrders":[{"$id":"8","ChangeOrderId":2,"ChangeOrderNumber":1823,"ChangeOrderDate":"2014-08-12T14:43:22.673","ChangeOrderName":"Insert Name Here","ChangeOrderDescription":"Work Orders","ChangeOrderAmount":4000,"ChangeOrderApprovedDate":"2014-08-12T14:43:22.673","ChangeOrderApprovedAmount":3000,"ChangeOrderApprovedNumber":2,"ChangeOrderAttn":"Rosie Sanchez","ChangeOrderHidden":false,"JobId":2,"Job":{"$ref":"5"}}]},{"$id":"9","JobId":3,"JobNumber":12398,"JobName":"City Center","JobDescription":"Remodeling Yard House","OriginalContract":56325412,"ContractDate":"2014-08-12T14:43:22.507","BillingDate":"2014-08-12T14:43:22.507","TotalCO":12502105,"RevisedContract":452136852,"Budget":854523658,"BillingForm":"Invoice","TESPM":"Frank Harvel","TESSuperintendent":"Shawn Saulnier","Status":"Active","MoreShit":"More shit goes here","TaxExempt":true,"CertPayroll":true,"JobCost":784556124,"RemainingBudget":96523145,"Profit":854125,"Percentage":45,"TotalBilled":45236554,"BalanceToBill":541256,"PaidToDate":0,"BalanceDue":89654123,"JobAddress":"1234 Mason Rd","JobCity":"Katy","JobState":"TX","JobZipcode":77493,"JobCounty":"Harris","JobPhone":2814256965,"JobFax":2814565325,"JobHidden":false,"Customers":[{"$id":"10","CustomerId":3,"CustomerName":"Twin Peaks","CustomerPhoneNumber":8327899667,"CustomerFaxNumber":7134568547,"CustomerAddress":"8473 Katy Fwy","CustomerCity":"Houston","CustomerState":"TX","CustomerZipcode":77043,"CustomerWebsite":"citycenter.com","CustomerOtherShit":"Other Shit Goes here","CustomerHidden":false,"CustomerPM":null,"CustomerAdmin":"Jane Miller","CustomerAccountant":"Betsy Sue","TESSuperintendent":null,"JobId":3,"Job":{"$ref":"9"}}],"Employees":[{"$id":"11","EmployeeId":1,"AccountName":"Not Sure","EmployeeFirstName":"Frank","EmployeeLastName":"Harvel","EmployeeTitle":"Manager","EmployeeCellPhone":2818567854,"EmployeeOfficePhone":7134527854,"EmployeeEmail":"texas45#gmail.com","CompanyEmployeeId":12521,"EmployeeHidden":false,"EmployeeIsSuper":true,"EmployeeIsPM":false,"JobId":3,"Job":{"$ref":"9"}}],"ChangeOrders":[{"$id":"12","ChangeOrderId":3,"ChangeOrderNumber":45324,"ChangeOrderDate":"2014-08-12T14:43:22.673","ChangeOrderName":"Insert Name Here","ChangeOrderDescription":"It changed again","ChangeOrderAmount":4000,"ChangeOrderApprovedDate":"2014-08-12T14:43:22.673","ChangeOrderApprovedAmount":3000,"ChangeOrderApprovedNumber":3,"ChangeOrderAttn":"Travis Dillard","ChangeOrderHidden":false,"JobId":3,"Job":{"$ref":"9"}}]}]
First of all, this is a work in progress. Your code is very large and to solve this I removed a lot o noise from your plunkr, I left there only what's essential to make it work and only the code involved in it.
Working Demo
First thing to notice, on your JobController you are doing:
////GET Jobs
$scope.jobArray = Job.query();
This worked on previous versions of angular, on the current version there is no automatic promise unwrapping anymore, so you must use the then function:
////GET Jobs
Job.query().then(function(retrievedData){
$scope.jobArray = retrievedData;
});
Notice that on the plunkr I "mocked" the returning of data using $q and a timeout, I actually cleaned the json leaving only the properties that are used on the table, just to make it simpler, you don't need to do that on your code ok? Just keep that part as it is.
Maybe you'll have to modify it just to resolve the promise with the returned data, but this is up to you, the important thing is to return a promise from your query() method and resolve it.
On the HTML I noticed that you are binding the customer name like this:
<td>{{job.Customers.CustomerName}}</td>
But on your Json, the Customers property is an array of customers, so you either return one customer from your api or bind it like this:
<td>{{job.Customers[0].CustomerName}}</td>
I also noticed that there are a lot of jQuery references on your controllers like this:
$('#editJobModal').modal();
This is not recommended and I don't think it will work at all, when dealing with the DOM, always use directives and comunicate with them using bindings, thats the angular way.
Well after all this, my plunkr is showing the table with the 2 fake customers from the Json. Now I suggest you to study that code and apply those principles to your app.
I hope I could help or at least point you at the right direction.

Error: No pending request to flush - when unit testing AngularJs service

I'm newbie to AngularJs, and I'm in the process of writing my first unit test; to test the service I wrote a test that simply returns a single Json object. However, everytime I run the test I get the error stated in the title. I don't know what exactly is causing this! I tried reading on $apply and $digest and not sure if that's needed in my case, and if yes how; a simple plunker demo would be appreciated.
here is my code
service
var allBookss = [];
var filteredBooks = [];
/*Here we define our book model and REST api.*/
var Report = $resource('api/books/:id', {
id: '#id'
}, {
query: {
method: 'GET',
isArray: false
}
});
/*Retrive the requested book from the internal book list.*/
var getBook = function(bookId) {
var deferred = $q.defer();
if (bookId === undefined) {
deferred.reject('Error');
} else {
var books= $filter('filter')(allBooks, function(book) {
return (book.id == bookId);
});
if (books.length > 0) {
deferred.resolve(books[0]);//returns a single book object
} else {
deferred.reject('Error');
};
};
return deferred.promise;
};
test
describe('unit:bookService', function(){
beforeEach(module('myApp'));
var service, $httpBackend;
beforeEach(inject(function (_bookService_, _$httpBackend_) {
service = _bookService_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', "/api/books/1").respond(200, {
"book": {
"id": "1",
"author": "James Spencer",
"edition": "2",
.....
}
});
}));
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
it('should return metadata for single report', function() {
service.getBook('1').then(function(response) {
expect(response.length).toEqual(1);
});
$httpBackend.flush();// error is in this line
});
});
error
Error: No pending request to flush !
at c:/myapp/bower_components/angular-mocks/angular-mocks.js:1439
at c:/myapptest/tests/bookTest.js:34
libs version
AngularJS v1.2.21
AngularJS-mock v1.2.21
I don't see where you're actually issuing a Report.query(). The getBook function just returns an unresolved promise that will never be resolved because nothing in the function is async.
You need to call Report.query via the book function with the promise resolved in the .then() (in the book function). After that, flush the http backend in the service.getBook().then() and do the expect.

Categories

Resources