Expected Array but received ...(JSON)... AngularJS Error - javascript

I'm learning Angular1 from Adam Freeman's ,,Pro AngularJS" book. I've got a problem with building a DeployD app he's describing in chapters 6-8 - it seems like my code doesn't want to read JSON
That's my HTML:
<!DOCTYPE html>
<html ng-app="sportsStore" lang="pl">
<head>
<title>SportsStore</title>
<script src="components/angular.js"></script>
<script src="components/angular-resource.js"></script>
<link href="components/bootstrap.css" rel="stylesheet" />
<link href="components/bootstrap-theme.css" rel="stylesheet" />
<script>
angular.module("sportsStore", ["customFilters"]);
</script>
<script src="controllers/sportsStore.js"></script>
<script src="filters/customFilters.js"></script>
<script src="controllers/productListControllers.js"></script>
</head>
<body ng-controller="sportsStoreCtrl">
<div class="navbar navbar-inverse">
<a class="navbar-brand" href="#">SKLEP SPORTOWY</a>
</div>
<div class="panel panel-default row" ng-controller="productListCtrl">
<div class="alert alert-danger" ng-show="data.error">
Błąd ({{data.error.status}}). Dane produktu nie zostały wczytane.
Kliknij tutaj, aby spróbować ponownie
</div>
<div class="panel panel-default row" ng-controller="productListCtrl"
ng-hide="data.error">
<div class="col-xs-3">
<a ng-click="selectCategory()"
class="btn btn-block btn-default btn-lg">Strona główna</a>
<a ng-repeat="item in data.products | orderBy:'category' |
unique:'category'" ng-click="selectCategory(item)" class=" btn btn-block
btn-default btn-lg" ng-class="getCategoryClass(item)">
{{item}}
</a>
</div>
<div class="col-xs-8">
<div class="well"
ng-repeat="item in data.products | filter:categoryFilterFn |
range:selectedPage:pageSize">
<h3>
<strong>{{item.name}}</strong>
<span class="pull-right label label-primary">
{{item.price | currency}}
</span>
</h3>
<span class="lead">{{item.description}}</span>
</div>
<div class="pull-right btn-group">
<a ng-repeat="page in data.products | filter:categoryFilterFn |
pageCount:pageSize" ng-click="selectPage($index + 1)" class="btn
btn-default" ng-class="getPageClass($index + 1)">
{{$index + 1}}
</a>
</div>
</div>
</div>
</body>
</html>
and the sportStore.js controller
angular.module("sportsStore")
.constant("dataUrl", "http://localhost:5500/products")
.controller("sportsStoreCtrl", function ($scope, $http, dataUrl) {
$scope.data = {};
$http.get(dataUrl)
.then(function (data) {
$scope.data.products = data;
},
function (error) {
$scope.data.error = error;
});
});
I'm using DeployD to build an API, and the problem is that when I try to run my app, the error shows up in console:
Error: [filter:notarray] Expected array but received:
{"data":[{"name":"Kajak","description":"Łódka przeznaczona dla jednej
osoby","category":"Sporty
Wodne","price":275,"id":"d9b9e4fcb9df3853"},{"name":"Kamizelka
ratunkowa","description":"Chroni i dodaje uroku","category":"Sporty
wodne","price":49.75,"id":"3c1cceedb44ddb84"},{"name":"Piłka","description":"Zatwierdzona
przez FIFA rozmiar i waga","category":"Piłka
Nożna","price":19.5,"id":"447a2079a8488932"},{"name":"Flagi
narożne","description":"Nadadzą Twojemu boisku profesjonalny
wygląd","category":"Piłka
Nożna","price":34.95,"id":"2b2dd597f18bb8a7"},{"name":"Stadion","description":"Składany
stadion na 35000 osób","category":"Piłka
Nożna","price":79500,"id":"2cfe0f6767240bf9"},{"name":"Czapka","description":"Zwiększa
efektywność mózgu o
75%","category":"Szachy","price":16,"id":"dfc137db43574b4a"},{"name":"Niestabilne
krzesło","description":"Zmniejsza szansę
przeciwnika","category":"Szachy","price":29,"id":"e2b644c5091d28ca"},{"name":"Ludzka
szachownica","description":"Przyjemna gra dla całej
rodziny","category":"Szachy","price":75,"id":"f945806bb011895d"},{"name":"Błyszczący
król","description":"Pokryty złotem i wysadzany diamentami
król","category":"Szachy","price":1200,"id":"fab242704bb38b64"}],"status":200,"config":{"method":"GET","transformRequest":[null],"transformResponse":[null],"jsonpCallbackParam":"callback","url":"http://localhost:5500/products","headers":{"Accept":"application/json,
text/plain, /"}},"statusText":"OK"}
http://errors.angularjs.org/1.6.0-rc.1/filter/notarray?p0=%7B%22data%22%3A%…son%2C%20text%2Fplain%2C%20*%2F*%22%7D%7D%2C%22statusText%22%3A%22OK%22%7D
at angular.js:68
at angular.js:20392
at fn (eval at compile (angular.js:15095), :4:388)
at regularInterceptedExpression (angular.js:16203)
at Scope.$digest (angular.js:17732)
at Scope.$apply (angular.js:18006)
at done (angular.js:12150)
at completeRequest (angular.js:12376)
at XMLHttpRequest.requestLoaded (angular.js:12304)
I tried to skim through similar errors on SO but none of the solutions seemed to work for me. Did someone have a similar problem?

ng repeat works with an arrays but as per the response getting from the API in then() method is not the data itself but it is having a property named as data which is the actual array that you have to pass in ng-repeat.
So, instead of using $scope.data.products = data use $scope.data.products = data.data
----------OR----------
.then(function (response) {
$scope.data.products = response.data;
}

The error message shows the filter refusing to process the response object instead of the data array. Expected array but received: {data:[..., headers: ...
The .then method of the $http service returns a response object, not data.
angular.module("sportsStore")
.constant("dataUrl", "http://localhost:5500/products")
.controller("sportsStoreCtrl", function ($scope, $http, dataUrl) {
$scope.data = {};
$http.get(dataUrl)
//.then(function (data) {
// $scope.data.products = data;
.then(function (response) {
$scope.data.products = response.data;
},
function (error) {
$scope.data.error = error;
});
});
Data is only one property of the response object:
$http(...).
then(function onSuccess(response) {
// Handle success
var data = response.data;
var status = response.status;
var statusText = response.statusText;
var headers = response.headers;
var config = response.config;
...
}, function onError(response) {
// Handle error
var data = response.data;
var status = response.status;
var statusText = response.statusText;
var headers = response.headers;
var config = response.config;
...
});

ng repeat and filter works with array, you need to access the data
angular.module("sportsStore")
.constant("dataUrl", "http://localhost:5500/products")
.controller("sportsStoreCtrl", function ($scope, $http, dataUrl) {
$scope.data = {};
$http.get(dataUrl)
.then(function (data) {
$scope.data.products = data.data;
},
function (error) {
$scope.data.error = error;
});
});

Angular expects the data variable to be type of array.
$scope.data = [];
Then try following code:
$http.get('dataUrl')
.success(function(data) {
$scope.data = data;
}).error(function(data, status) {
$log.error('Error ' + status + ' unable to get data from server.');
});
Also remember to add to your controller the $log to properly display bugs in console:
.controller('sportsStoreCtrl', ['$scope', '$http', '$log', function ($scope, $http, $log)

Related

AngularJS: Get template attribute value in controller

I am a newbie of angularjs using version 1.6.4. I am using this module leon/angular-upload for upload functionality, minify version. On successful upload request, server return json object of uploaded file information on onSuccess(response) function as you can see in my user-registration.template.html file. Now i need to take this json object to my controller so that i can save this information in my database. Below is the few lines of my code.
user-registration.template.html:
<form role="form">
<div class="form-group float-label-control">
<label>Name</label>
<input type="text" placeholder="Name" class="form-control" ng-model="model.user.name">
</div>
<!-- leon/angular-upload -->
<div upload-button
url="/user_uploads"
on-success="onSuccess(response)"
on-error="onError(response)">Upload</div>
<div class="text-center">
<button type="button" class="btn btn-default" ng-click="model.save(model.user)">Save</button>
</div>
</form>
My component "user-registration.component.js":
(function(){
"use strict";
var module = angular.module(__appName);
function saveUser(user, $http){
var url = user.id > 0 ? __apiRoot + "/users/" + user.id : __apiRoot + "/users";
var dataObj = {
payload: JSON.stringify(user),
_method: "PUT"
}
return $http.post(url, dataObj);
}
function controller($http){
var model = this;
model.user = null;
model.save = function(user){
console.log(JSON.stringify(user));
saveUser(user, $http).then(function(response){
alert(response.data.msg);
});
}
}
module.component("userRegistration", {
templateUrl: "components/user-registration/user-registration.template.html",
bindings: {
value: "<"
},
controllerAs: "model",
controller: ["$http", controller]
});
}());
Try to put your server response data to rootScope model for Exempel :
$rootScope.serveResponse = response ;
and with this rootScope you can share your variable data between controller

Consume API Rest from AngularJS

the purpose of this question it´s because i do not know why i can not get this done.
First i have my api in nodejs + mongodb, and using POSTMAN i can see my api on http://localhost:3000/api/.
Now in AngularJS i have my routes, i have my service calling my api but when i run it i have this error:
angular.js:11756 GET http://localhost:8080/api/platillos 404 (Not Found), i thinks it´s due to my api is on port 3000 and my web is running on port 8080, but im not sure this is the problem, this is my code:
service.js
use strict';
angular.module("nightshift")
.constant("baseURL", "/api/")
.service("menuService", ["$http", "baseURL", function($http, baseURL) {
this.getPlatillos = function() {
return $http.get(baseURL + "platillos");
}
this.getPlatillo = function(index) {
return $http.get(baseURL + "platillos/" + index);
}
}])
controllers.js
'use strict';
angular.module("nightshift")
.controller("MenuController", ["$scope", "menuService", function($scope, menuService) {
$scope.dishes = {};
menuService.getPlatillos()
.then(function(response) {
console.log("nice");
console.log(response.data);
$scope.dishes = response.data;
},
function(response) {
console.log("hola" + response.statusText);
})
}]);
my view Platillos.html
<div class = "container">
<div class = "row row-content" ng-controller = "MenuController">
<div class = "col-xs-12 col-sm-10">
<ul class = "media-list">
<li class = "media" ng-repeat = "dish in dishes">
<div class = "media-left media-middle">
<a href = "#">
<img ng-src = {{dish.image}} class = "media-object img-thumbnail">
</a>
</div>
<div class = "media-body">
<h2 class = "media-heading">{{dish.name}}
<span class = "badge">{{dish.price | currency}}</span>
</h4>
<p>{{dish.description}}</p>
</div>
</li>
</ul>
</div>
</div>
</div>
hope someone can help me

Angular not updating page after http request (scope issue?)

When my page loads, all the items in my mongo db are displayed. I have a form to input new entries, or delete entries. When creating or deleting, the http process works, but the new data is not updated in the DOM.
Most of the related questions I have researched suggest to make sure my ng-controller wraps the entire body, which it does. Other's suggest to use $apply, but I've also read that this is wrong. When I try it, I am alerted "in progress" anyway.
My only guess is that after the http request, a new scope is loaded and angular doesn't pick up on that. Or for some reason its just not reloading the data after my request. Here is my code, thanks for your help.
index.html
<body ng-controller="MainController">
<!-- list records and delete checkbox -->
<div id="record-list" class="row">
<div class="col-sm-4 col-sm-offset-4">
<!-- loop over records in $scope.records -->
<div class="checkbox" ng-repeat="record in records">
<label>
<input type="checkbox" ng-click="deleteRecord(record._id)">
{{ record.artist}} - {{ record.album }} - {{ record.bpm}}
</label>
</div>
</div>
</div>
<!-- record form data -->
<div id="record-form" class="row">
<div class="col-sm-8 col-sm-offset-2 text-center">
<form>
<div class="form-group">
<input type="artist" class="form-control input-lg text-center" placeholder="Artist" ng-model="formData.artist">
</div>
<div class="form-group">
<input type="album" class="form-control input-lg text-center" placeholder="Album" ng-model="formData.album">
</div>
<div class="form-group">
<input type="bpm" class="form-control input-lg text-center" placeholder="BPM" ng-model="formData.bpm">
</div>
<button type="submit" class="btn btn-primary btn-lg" ng-click="createRecord()">Add</button>
</form>
</div>
</div>
</div>
controller.js
angular.module('myApp', []).controller('MainController', ['$scope', '$http', function ($scope, $http) {
$scope.formData = {};
$scope.sortType = 'artist';
$scope.sortReverse = false;
//$scope.searchRecords = '';
$http.get('/api/records/')
.success(function(data) {
$scope.records = data;
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
$scope.createRecord = function() {
$http.post('/api/records/', $scope.formData)
.success(function(data) {
//$scope.formData = {};
$scope.records = data;
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
};
$scope.deleteRecord = function(id) {
$http.delete('/api/records/' + id)
.success(function(data) {
$scope.records = data;
console.log("delete record scope: " + data);
})
.error(function(data) {
console.log('Error: ' + data);
});
};
}])
Your controller JS looks fine - I would say from looking at this that you need to export the updated values from your mongoDB collection when the POST/DELETE is successful.
If you use Mongoose (mongoDB plugin), you can update your API code to send back the updated data upon success with something like this:
// POST
// --------------------------------------------------------
// Provides method for saving new record to the db, then send back list of all records
app.post('/api/records', (req, res) => {
// Creates a new record based on the Mongoose Schema
const newRecord= new Record(req.body);
// New record is saved to the db
newRecord.save((err) => {
// Test for errors
if(err) res.send(err);
// Now grab ALL data on records
const all = Records.find({});
all.exec((err, records) => {
// Test for errors
if(err) res.send(err);
// If no errors are found, it responds with JSON for all records
res.json(records);
});
});
});

GET JSONP data from php file in Angular Controller

Recently, I began to study Angular. So much I do not know. I'm trying to get json data from a php file to use within an Angular controller. But the data from php file does not exceed.
controllers.js:
app.controller('MainCtrl',['$scope', '$resource', '$http',
function($scope, $resource,$http) {
$http.get('/xbmc.php').success(function(data) {
$scope.data = data;
});
}]);
xbmc.php:
<?
include('sys/inc/config.inc.php');
include(SMARTY_DIR.'Smarty.class.php');
include(BASE_DIR .'sys/inc/classes.inc.php');
include(BASE_DIR .'sys/inc/init.inc.php');
include(BASE_DIR .'xbmcApi.php');
$jsonData = new xbmcApi($_GET['action']);
/**
if (MEGAKINO_LOGED)
{
**/
$json = $jsonData->getResult();
/**
}
else
$json = array('authStatus' => '0');
**/
echo json_encode($json);
?>
index.html:
<body ng-controller="MainCtrl">
<div class="wrapper">
<h2>{{title}}</h2>
<div class="row">
<div class="col-md-1 col-sm-2 col-xs-4" style="margin-top: 0.5%;" ng-repeat="item in data.items">
<div class="image" style="margin-bottom: 1%">
<a data-ng-href="#!/seasons/serie/{{item.id}}">
<img data-ng-src="/files/series/thumb-{{item.id}}.jpg" alt=""/>
</a>
</div>
<div class="info">
<a data-ng-href="#!/seasons/serie/{{item.id}}">
<b>{{item}}</b>
<u>Рейтинг: {{item.rate}}</u>
</a>
</div>
</div>
</div>
</div>
</body>
Your php code tells that your json will be build if a $_GET['action'] param is passed:
$jsonData = new xbmcApi($_GET['action']);
Yet, you are not passing any data as a query string from your angular controller. Try something like:
app.controller('MainCtrl',['$scope', '$resource', '$http',
function($scope, $resource,$http) {
$http({
url: '/xbmc.php',
method: "GET",
params: {action: 'some_action'}
}).success(function(data) {
$scope.data = data;
});
}]);
AS #CharlieH said, check for errors on your console:
app.controller('MainCtrl',['$scope', '$resource', '$http',
function($scope, $resource,$http) {
$http.get('/xbmc.php')
.then(function(response) {
$scope.data = response.data;
})
.catch (function(error) {
//check for errors here
console.log(error);
throw error;
});
}]);
Also the .success method has been deprecated. We should all be migrating to using .then and .catch. For more information on that see: Deprecation of the .success and .error methods in the $http service

Getting undefined in AngularJS

I'm working on building a little app that accepts input from a form (the input being a name) and then goes on to POST the name to a mock webservice using $httpBackend. After the POST I then do a GET also from a mock webservice using $httpBackend that then gets the name/variable that was set with the POST. After getting it from the service a simple greeting is constructed and displayed back at the client.
However, currently when the data gets displayed now back to the client it reads "Hello undefined!" When it should be reading "Hello [whatever name you inputed] !". I used Yeoman to do my app scaffolding so I hope everyone will be able to understand my file and directory structure.
My app.js:
'use strict';
angular
.module('sayHiApp', [
'ngCookies',
'ngMockE2E',
'ngResource',
'ngSanitize',
'ngRoute'
])
.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'MainCtrl'
})
.otherwise({
redirectTo: '/'
});
})
.run(function($httpBackend) {
var name = 'Default Name';
$httpBackend.whenPOST('/name').respond(function(method, url, data) {
//name = angular.fromJson(data);
name = data;
return [200, name, {}];
});
$httpBackend.whenGET('/name').respond(name);
// Tell httpBackend to ignore GET requests to our templates
$httpBackend.whenGET(/\.html$/).passThrough();
});
My main.js:
'use strict';
angular.module('sayHiApp')
.controller('MainCtrl', function ($scope, $http) {
// Accepts form input
$scope.submit = function() {
// POSTS data to webservice
setName($scope.input);
// GET data from webservice
var name = getName();
// Construct greeting
$scope.greeting = 'Hello ' + name + ' !';
};
function setName (dataToPost) {
$http.post('/name', dataToPost).
success(function(data) {
$scope.error = false;
return data;
}).
error(function(data) {
$scope.error = true;
return data;
});
}
// GET name from webservice
function getName () {
$http.get('/name').
success(function(data) {
$scope.error = false;
return data;
}).
error(function(data) {
$scope.error = true;
return data;
});
}
});
My main.html:
<div class="row text-center">
<div class="col-xs-12 col-md-6 col-md-offset-3">
<img src="../images/SayHi.png" class="logo" />
</div>
</div>
<div class="row text-center">
<div class="col-xs-10 col-xs-offset-1 col-md-4 col-md-offset-4">
<form role="form" name="greeting-form" ng-Submit="submit()">
<input type="text" class="form-control input-field" name="name-field" placeholder="Your Name" ng-model="input">
<button type="submit" class="btn btn-default button">Greet Me!</button>
</form>
</div>
</div>
<div class="row text-center">
<div class="col-xs-12 col-md-6 col-md-offset-3">
<p class="greeting">{{greeting}}</p>
</div>
</div>
At the moment your getName() method returns nothing. Also you cant just call getName() and expect the result to be available immediately after the function call since $http.get() runs asynchronously.
You should try something like this:
function getName () {
//return the Promise
return $http.get('/name').success(function(data) {
$scope.error = false;
return data;
}).error(function(data) {
$scope.error = true;
return data;
});
}
$scope.submit = function() {
setName($scope.input);
//wait for the Promise to be resolved and then update the view
getName().then(function(name) {
$scope.greeting = 'Hello ' + name + ' !';
});
};
By the way you should put getName(), setName() into a service.
You can't return a regular variable from an async call because by the time this success block is excuted the function already finished it's iteration.
You need to return a promise object (as a guide line, and preffered do it from a service).
I won't fix your code but I'll share the necessary tool with you - Promises.
Following angular's doc for $q and $http you can build yourself a template for async calls handling.
The template should be something like that:
angular.module('mymodule').factory('MyAsyncService', function($q, http) {
var service = {
getNames: function() {
var params ={};
var deferObject = $q.defer();
params.nameId = 1;
$http.get('/names', params).success(function(data) {
deferObject.resolve(data)
}).error(function(error) {
deferObject.reject(error)
});
return $q.promise;
}
}
});
angular.module('mymodule').controller('MyGettingNameCtrl', ['$scope', 'MyAsyncService', function ($scope, MyAsyncService) {
$scope.getName = function() {
MyAsyncService.getName().then(function(data) {
//do something with name
}, function(error) {
//Error
})
}
}]);

Categories

Resources