AngularJS deferred $http.get response, empty array - angularjs

Please help in changing this code to be able to use $http.get html, at the moment the resulting array (html_controls) is empty. However, I can see the response in the console for all the request in $http.get. Thank you.
angular.module('exodus-grid').controller('DynamicPropertiesController', ['$scope', '$http', '$templateCache', '$q', 'coreFactory',
function($scope, $http, $templateCache, $q, coreFactory) {
//$scope.DynamicProperties = 'Property being added to the controller.';
//coreFactory.fetchData('http://uat.resources.newscdn.com.au/cs/networksales/products/latest/products.json', 'products');
// TODO: Change this harcoded value to the products.json in s3
$scope.products = [{
"id": "btyb",
"label": "BTYB + Superskin",
"description": "",
"name": "btyb",
"active": true,
"properties": [{
"bannerLink": [{
"tmp_prop_name": "bannerLink",
"label": "Header Tracking Link (Desktop)",
"type": "textbox"
}],
"superskinLink": [{
"tmp_prop_name": "superskinLink",
"label": "Sideskin Tracking Link (Desktop)",
"type": "textbox"
}],
"ImgUrl": [{
"tmp_prop_name": "ImgUrl",
"label": "Header Image Url",
"type": "textbox"
}]
}]
}, {
"id": "iframe",
"label": "iframe",
"description": "",
"name": "iframe",
"active": true,
"properties": [{
"link": [{
"tmp_prop_name": "link",
"label": "iFrame source Url",
"type": "textbox"
}]
}]
}];
var requests = [];
var html_controls = [];
var product = $scope.products[0];
var properties = angular.fromJson(product.properties);
//console.log(angular.toJson(properties));
angular.forEach(properties, function(property) {
angular.forEach(property, function(item) {
//console.log(angular.toJson(property));
if (item[0].type === "textbox") {
//console.log(angular.toJson(item));
//console.log(Object.getOwnPropertyNames(property));
//console.log(Object.keys(property));
$http.get("plugins/k-plugin-exodus-grid/templates/properties/textbox.html").success(function(html) {
html = html.replace("%%label%%", item[0].label);
html = html.replace("%%scope%%", item[0].tmp_prop_name);
//console.log(html);
html_controls.push(html);
console.log(html_controls);
var deferred = $q.defer();
requests.push(deferred.promise);
console.log(deferred, deferred)
}).then(function() {
//$scope.html = html_controls;
});
}
});
});
//console.log(html_controls);
//$scope.html = html_controls;
$q.all(requests).then(function(data) {
console.log("12312312 " , data);
$scope.html = html_controls;
});
}
]);

Looks like you are trying to resolve a array of empty promises. Since it is running async, when $q.all() us called, requests[] is still empty.
Try building an array of promises and then resolve this using q.all() instead:
var requests = []; // a list of promises
angular.forEach(properties, function(property) {
angular.forEach(property, function(item) {
var promise = $http.get("/yoururl"); // $http.get returns a promise
requests.push(promise); // add to list of requests as a promise
});
});
$q.all(requests).then(function (result) {
console.log('results' + result);
});

Related

Angular $http service not getting objects from .JSON file

Here is my http service code:
app.controller('StoreController', ['$http', function($http){
var store = this;
store.products = [];
$http.get('/store-products.json').then(function(data){
store.products = data;
});
}]);
And here is my JSON code:
[
{
"name": "...",
"price": 20.00,
"description": "...",
"canPurchase": false,
"images": [
"...jpg",
"...jpg",
"...jpg"
],
"reviews": []
},
{
"name": "...",
"price": 15.95,
"description": "...",
"canPurchase": true,
"images": [],
"reviews": []
}
]
When I run the code on localhost server, it does not show my objects. There is also no errors in the console that show so I cannot see where I am going wrong. Can anyone see the issue here?
your json data is wrapped at response.data of $http.get.
change to below code will solve the problem(also make sure your json file is at right location).
$http.get('/store-products.json').then(function(res){
store.products = res.data;
});
Plunker demo.

Asynchronous Angular-bootsrap-UI typeahead: select directive issue

My application is using the Angular-Bootstrap-UI-Typeahead feature for auto complete.
As the user types, i'd like to be able to call an API & return similar strings.
I've followed the guidance here, and everything works fine with the out of box Google API.
I've also successfully swapped in my own API: I am able to call the API, get the data, and log it in the correct format in my browser console.
However, I constantly get "no results found" from the text box. I suspect this may be a problem with the select directive, but i am stumped.
I would greatly appreciate any guidance on this!
Here is some code:
UI (content.html)
<h4>biz results</h4>
<pre>Model: {{user.orgName | json}}</pre>
<input type="text"
ng-model="user.orgName"
placeholder="Locations loaded via $http"
uib-typeahead="obj for obj in getLocation($viewValue)"
typeahead-loading="loadingBiz"
typeahead-no-results="noBiz" class="form-control"
typeahead-wait-ms="700">
<i ng-show="loadingBiz" class="glyphicon glyphicon-refresh"></i>
<div ng-show="noBiz">
<i class="glyphicon glyphicon-remove"></i> No Results Found
</div>
Angular (script.js)
$scope.getLocation = function(val) {
var bizRequest = $http.post('/sample', {
// var bizRequest = $http.post('/biz', {
orgName: val,
limit: 5
}
).success(function(response){
console.log(response)
//console.log('Biz response: ' + JSON.stringify(response))
//console.log(response.data.fields.map(item))
var bizArray = response.data.fields.map(function(item){
return item.fields.orgName;
});
console.log(bizArray);
return bizArray;
});
console.log("Biz Request /////// " + JSON.stringify(bizRequest))
return bizRequest
};
Node API (app.js)
app.post('/sample', function(req, res){
var resp = {
"success": true,
"data": {
"fields": [{
"fields": {
"scid": "1111",
"orgName": "1111",
"countryCode": "1",
"countryName": "1",
"cityName": "1",
"addressLine": "1111"
},
"matchedRule": {
"duplicateLevel": "POTENTIAL_MATCH",
"id": "18",
"rank": "1"
}
}, {
"fields": {
"scid": "2222",
"orgName": "2222",
"countryCode": "22",
"countryName": "22",
"cityName": "22",
"addressLine": "2 22"
},
"matchedRule": {
"duplicateLevel": "POTENTIAL_MATCH",
"id": "18",
"rank": "1"
}
}]
},
"errors": [],
"warnings": [],
"infoMessages": []
}
res.send(JSON.stringify(resp))
})
You have to return promise from getLocation method while dealing asynchronous typeahead. So don't use .success there which would break promise chain. Instead use .then which would help you to chain promise and you can return data from .then to pass it to typeahead
$scope.getLocation = function(val) {
var bizRequest = $http.post('/sample', {
// var bizRequest = $http.post('/biz', {
orgName: val,
limit: 5
}
).then(function(data){
response = data.data; //<-- take data in response.
console.log(response.data)
//console.log('Biz response: ' + JSON.stringify(response))
//console.log(response.data.fields.map(item))
var bizArray = response.data.fields.map(function(item){
return item.fields.orgName;
});
console.log(bizArray);
return bizArray;
});
console.log("Biz Request /////// " + JSON.stringify(bizRequest))
return bizRequest
};

angular service test fails to return required response

I am trying to write tests for angular service using jasmine and karma. I have the following code for my service call:
angular.module('omdb', [])
.factory('myservice', MyService);
MyService.$inject = ['$http'];
function MyService($http) {
var vm = this;
var service = {};
service.getData = function() {
return $http.get('omdb/mydata.json').then(function(response) {
return response.data;
});
};
return service;
};
I am tesitng it using the following file for spec as:
describe('myservice', function() {
var mockservicedata = [{
"name": "value1",
"id": "1"
}, {
"name": "value2",
"id": "2"
}, {
"name": "value3",
"id": "3"
}];
var myservice = {};
beforeEach(module('omdb'));
beforeEach(inject(function(_myservice_) {
myservice = _myservice_;
}));
it('should return search myservice data', function() {
expect(myservice.getData()).toEqual(mockservicedata);
});
});
which basically throws an error as:
Expected d({ $$state: Object({ status: 0 }) }) to equal [ Object({ name: 'value1', id: '1' }), Object({ name: 'value2', id: '2' }), Object({ name: 'value3', id: '3' }) ].
stack#http://localhost:59239/movie-app/lib/jasmine-2.3.4/jasmine.js:1482:17
buildExpectationResult#http://localhost:59239/movie-app/lib/jasmine-2.3.4/jasmine.js:1452:14
Env/expectationResultFactory#http://localhost:59239/movie-app/lib/jasmine-2.3.4/jasmine.js:583:18
Spec.prototype.addExpectationResult#http://localhost:59239/movie-app/lib/jasmine-2.3.4/jasmine.js:324:29 addExpectationResult#http://localhost:59239/movie-app/lib/jasmine-2.3.4/jasmine.js:533:16
Expectation.prototype.wrapCompare/<#http://localhost:59239/movie-app/lib/jasmine-2.3.4/jasmine.js:1406:7
#http://localhost:59239/movie-app/spec/omdb/myservice.spec.js:14:9
attemptSync#http://localhost:59239/movie-app/lib/jasmine-2.3.4/jasmine.js:1789:9
QueueRunner.prototype.run#http://localhost:59239/movie-app/lib/jasmine-2.3.4/jasmine.js:1777:9 QueueRunner.prototype.execute#http://localhost:59239/movie-app/lib/jasmine-2.3.4/jasmine.js:1762:5
Env/queueRunnerFactory#http://localhost:59239/movie-app/lib/jasmine-2.3.4/jasmine.js:627:7
Spec.prototype.execute#http://localhost:59239/movie-app/lib/jasmine-2.3.4/jasmine.js:353:5 executeNode/<.fn#http://localhost:59239/movie-app/lib/jasmine-2.3.4/jasmine.js:2360:32 attemptAsync#http://localhost:59239/movie-app/lib/jasmine-2.3.4/jasmine.js:1819:9
QueueRunner.prototype.run#http://localhost:59239/movie-app/lib/jasmine-2.3.4/jasmine.js:1774:9
QueueRunner.prototype.execute#http://localhost:59239/movie-app/lib/jasmine-2.3.4/jasmine.js:1762:5
Env/queueRunnerFactory#http://localhost:59239/movie-app/lib/jasmine-2.3.4/jasmine.js:627:7
executeNode/<.fn#http://localhost:59239/movie-app/lib/jasmine-2.3.4/jasmine.js:2345:13 attemptAsync#http://localhost:59239/movie-app/lib/jasmine-2.3.4/jasmine.js:1819:9
QueueRunner.prototype.run#http://localhost:59239/movie-app/lib/jasmine-2.3.4/jasmine.js:1774:9
QueueRunner.prototype.execute#http://localhost:59239/movie-app/lib/jasmine-2.3.4/jasmine.js:1762:5
Env/queueRunnerFactory#http://localhost:59239/movie-app/lib/jasmine-2.3.4/jasmine.js:627:7
TreeProcessor/this.execute#http://localhost:59239/movie-app/lib/jasmine-2.3.4/jasmine.js:2209:7
Env/this.execute#http://localhost:59239/movie-app/lib/jasmine-2.3.4/jasmine.js:678:7
window.onload#http://localhost:59239/movie-app/lib/jasmine-2.3.4/boot.js:110:5
I don't understand why it does not return data to the test. please help
Calling myservice.getData() won't actually give you the data you're expecting.
Since your getData method from MyService relies on $http's get method, you should be mocking it and then expecting that data returned.
So your test case should be like:
describe('myservice', function() {
var mockservicedata = [{
"name": "value1",
"id": "1"
}, {
"name": "value2",
"id": "2"
}, {
"name": "value3",
"id": "3"
}];
var myservice = {};
beforeEach(module('omdb'));
beforeEach(inject(function(_myservice_, _$httpBackend_) {
myservice = _myservice_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', "omdb/mydata.json").respond({
status: 200,
data: mockservicedata
});
}));
it('should return search myservice data', function() {
var response = myservice.getData()
response.then(function(response) {
expect(response.data).toEqual(mockservicedata);
});
$httpBackend.flush();
});
});
Hope this helps.
getData() will never return data instead it will return promise object.
If you want to test it then firstly you would have to mock the data for service then you can call it and match the result in the success handler.
Code is attached below:
describe('myservice', function() {
var mockservicedata = [{
"name": "value1",
"id": "1"
}, {
"name": "value2",
"id": "2"
}, {
"name": "value3",
"id": "3"
}];
var myservice, httpBackend;
beforeEach(module('omdb'));
beforeEach(inject(function(_myservice_, $httpBackend) {
myservice = _myservice_;
httpBackend = $httpBackend;
}));
it('should return search myservice data', function() {
httpBackend.when("GET", "omdb/mydata.json").respond(mockservicedata);
var promise = myservice.getData();
promise.then(function(response) {
expect(response.data).toEqual(mockservicedata);
});
httpBackend.flush();
});
});

Error while running angularJS unit test case in Karma-Jasmine

MainCtrl.js
var app = angular.module('mailApp');
app.controller('MainCtrl', ['$scope','$http',function($scope,$http) {
$scope.sortType = 'date'; // set the default sort type
$scope.sortReverse = false; // set the default sort order
$scope.inboxDetails = [];
$scope.loadInboxData = function(a){
if(a==1){
$http.get('inboxData.json')
.then(function(response){
$scope.inboxData = response.data;
});}
else if(a==2){
$http.get('inboxData1.json')
.then(function(response){
$scope.inboxData = response.data;
});}
}
//-----------------------------------------------
testMainCtrl.js
'use strict';
describe('MainCtrl', function () {
var $controller;
beforeEach(module('mailApp'));
beforeEach(inject(function(_$controller_){
$controller = _$controller_;
}));
//Test cases to verify Inbox Data
describe('$scope.loadInboxData', function () {
it('Inbox data is called', function () {
var $scope = {};
var controller = $controller('MainCtrl', {$scope: $scope});
$scope.inboxData = [{"subject": "Angular Example 11", "date": "3/8/2016", "to": "test1", "from":"abcd1","details":"Test Message 1" },{ "subject": "Angular Example 21", "date": "3/8/2016", "to": "test2", "from":"abcd2","details":"Test Message 2" },{ "subject": "Angular Example 31", "date": "4/8/2016", "to": "test3", "from":"abcd3","details":"Test Message 3" },{ "subject": "Angular Example 41", "date": "5/8/2016", "to": "test3", "from":"abcd4","details":"Test Message 4" }];
var a=$scope.loadInboxData(1);
expect($scope.inboxData).toEqual(a);
});
});
});
//------------------------------------------------
Error :
Chrome 48.0.2564 (Windows 10 0.0.0) MainCtrl $scope.loadInboxData
Inbox data is called FAILED
Expected
[
Object( {
subject:'Angular Example 11',
date:'3/8/2016',
to:'test1',
from:'abcd1',
details:'Test Message 1'
} ),
Object( {
subject:'Angular Example 21',
date:'3/8/2016',
to:'test2',
from:'abcd2',
details:'Test Message 2'
} ),
Object( {
subject:'Angular Example 31',
date:'4/8/2016',
to:'test3',
from:'abcd3',
details:'Test Message 3'
} ),
Object( {
subject:'Angular Example 41',
date:'5/8/2016',
to:'test3',
from:'abcd4',
details:'Test Message 4'
} )
]
to equal undefined.
You have a hard dependency on $http in your test. You should mock a return value from the $http service.
Take a look at the documentation https://docs.angularjs.org/api/ngMock/service/$httpBackend.
This may help you, $httpBackend is mock of $http
'use strict';
describe('MainCtrl', function () {
var $controller,$httpBackend;
beforeEach(module('mailApp'));
beforeEach(inject(function(_$controller_){
$controller = _$controller_;
}));
beforeEach(inject(function($injector) {
$httpBackend = $injector.get('$httpBackend');
}));
//Test cases to verify Inbox Data
describe('$scope.loadInboxData', function () {
it('Inbox data is called', function () {
var $scope = {};
var controller = $controller('MainCtrl', {$scope: $scope});
$scope.inboxData = [{"subject": "Angular Example 11", "date": "3/8/2016", "to": "test1", "from":"abcd1","details":"Test Message 1" },{ "subject": "Angular Example 21", "date": "3/8/2016", "to": "test2", "from":"abcd2","details":"Test Message 2" },{ "subject": "Angular Example 31", "date": "4/8/2016", "to": "test3", "from":"abcd3","details":"Test Message 3" },{ "subject": "Angular Example 41", "date": "5/8/2016", "to": "test3", "from":"abcd4","details":"Test Message 4" }];
$httpBackend.when('GET', 'inboxData.json').respond(yourjsonresponseData1);
$httpBackend.when('GET', 'inboxData2.json').respond(yourjsonresponseData2);
var a=$scope.loadInboxData(1);
expect($scope.inboxData).toEqual(a);
});
});
});

Backbone (Marionette) fetch in a collection returns an empty array (nested models)

I'm working with nested models and collections in Backbone (Marionette).
// Basic unit
Models.User = Backbone.Model.extend({});
Models.Users = Backbone.Collection.extend({ model: Models.User });
// A Group has a collection of Users
Models.Group = Backbone.Model.extend({
initialize: function() {
var users = new Models.Users(this.get("users"));
this.set("users", users);
}
});
Models.Groups = Backbone.Collection.extend({ model: Models.Group });
// An Organization has a collection of Groups
Models.Organization = Backbone.Model.extend({
initialize: function() {
var groups = new Models.Groups(this.get("groups"));
this.set("groups", groups);
}
});
Models.Organizations = Backbone.Collection.extend({
model: Models.Organization,
url: "./data/data.json"
});
My understanding is that this.get will return an array of objects (as determined via the data.json file) and convert it to a Backbone Collection.
The data.json file has the following structure:
[{
"id": "org1",
"groups": [{
"id": "group1",
"users": [
{ "name": "Alice" },
{ "name": "Bob" }
]
},
{
"id": "group2",
"users": [{ "name": "Charlie" }]
}]
},
{
"id": "org2",
"groups": [{
"id": "groupA",
"users": [{ "name": "Eve" }]
},
{
"id": "groupB",
"users": [
{ "name": "Linda" },
{ "name": "Mallory" }
]
}]
}]
I'm trying to populate the top-most collection (an Organization) with the data from data.json.
In index.html, I have:
<script type="text/javascript">
$(document).ready(function() {
MyApp.OrgManager.addInitializer(function() {
var data = new MyApp.Models.Organizations();
data.fetch({
success: function(collection) {
console.log("Success", collection);
}
});
});
MyApp.start();
});
</script>
fetch returns successfully, but the output of my console for the collection is an empty array. What went wrong?
Solved it. Had to make sure that
I was running the page on a local webserver, since jQuery doesn't like null origin XMLHttpRequests, and
I had to _.bindAll a few things so that this had a proper context.

Resources