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

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);
});
});
});

Related

Angular values do not reflect in scope until view changes

Below is my HTML code :
<div class="container-fluid">
<div class="jumbotron" id="welcomehead">
<br><br><br><br><br><br><br><br><br><br>
</div>
<div class="row">
<div class="col-md-12">
<h2>Welcome {{username }}, your Season total is {{total }}</h2>
</div>
</div>
<div class="row">
<div class="col-md-12">
<h3 id="slogan" >5 teams; 1 Goal</h3><br>
<img src="http://res.cloudinary.com/deji/image/upload/v1508887997/ymkit_ww8np1.jpg">
<img src="http://res.cloudinary.com/deji/image/upload/v1508888352/indkit_zop1gx.jpg">
<img src="http://res.cloudinary.com/deji/image/upload/v1508887290/chad2kit_fa3lrh.jpg">
<img src="http://res.cloudinary.com/deji/image/upload/v1508887718/fbg2kit_lzndap.jpg">
<img src="http://res.cloudinary.com/deji/image/upload/v1508888206/vgc_kit_hvpdz4.jpg">
</div>
</div>
Below is the javascript code for the html code:
'use strict';
angular.module('TNF.welcome', ['ngRoute', 'firebase'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/welcome',{
templateUrl:'welcome/welcome.html',
controller: 'WelcomeCtrl'
});
}])
.controller('WelcomeCtrl',['$scope','$firebaseAuth','CommonProp','$location','DatabaseService',
function($scope,$firebaseAuth, CommonProp,$location, databaseService){
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
databaseService.users.child(user.uid).once('value', function(usersSnapshot){
var users = usersSnapshot.val();
var total = users.total;
$scope.username = user.email;
$scope.total = total;
}, function(err) {
console.log(err);
$scope.total = 0;
});
} else {
// No user is signed in.
$location.path('/home');
}
});
$scope.logout = function(){
firebase.auth().signOut().then(function() {
console.log('Signed Out');
$location.path('/home');
}, function(error) {
console.error('Sign Out Error', error);
});
};
MY Issue
My issue is that the {{username}} and {{total}} values, which are results of the firebase query do not show in the view once the page loads. However, the values show up once I leave the page and then return to the view. Does this mean that the HTML code loads faster than the firebase query can be resolved? If so, is there a way to make the page only load AFTER the firebase query is resolved?
you'll need to let angular know to run an update.
$scope.username = user.email;
$scope.total = total;
$scope.$apply();

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

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

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)

How to pass data one page to another page using angular js?

Here I am Trying to Login with user credientials
if user is valid , I want to pass UserName,LastloginTime,Role values to another page using angular js
<form role="form" ng-app="MyApp" ng-controller="MasterController">
<div class="form-group">
<label>
Username</label>
<input type="text" class="form-control" placeholder="Username" required ng-model="username" />
</div>
<div class="form-group">
<label>
Password</label>
<input type="password" class="form-control" placeholder="Password" required ng-model="password" />
</div>
<div class="checkbox">
<label>
<input type="checkbox" ng-model="remember">
Remember my Password
</label>
</div>
<input type="button" value="Submit" ng-click="GetData()" class="btn btn-danger" />
<%--<button type="button" class="btn btn-danger" ng-click="GetData()">Submit</button>--%>
<span ng-bind="Message"></span>
</form>
js file here
$scope.GetData = function () {
debugger;
var data = { UserName: $scope.username, Password: $scope.password };
$http.post("api/Test/CheckUsername", data)
.success(function (data, status, headers, config) {
if (data != "") {
$scope.Employees = data;
window.location.href = "EmployeeMaster";
//$scope.Reporting = data;
}
else {
alert("Invalid Credientials");
}
});
}
I want to display values in a master page
<table class="table">
<tr ng-repeat="Emp in Employees">
<th>User </th>
<td>:</td>
<td>{{Emp.username}}</td>
</tr>
<tr>
<th>Designation </th>
<td>:</td>
<td>{{Emp.RoleName}}</td>
</tr>
<tr>
<th>Last Login </th>
<td>:</td>
<td>{{Emp.LastLogin}}</td>
</tr>
</table>
How can i pass the values login page to Home page?
I suggest creating a service to store your global data:
myApp.factory('DataService', function() {
var user = {
name: '',
role: ''
// and so on
};
return {
user: user
};
});
Just inject this to all your controllers and set and retrieve the data you need:
myApp.controller('MyCtrl', function($scope, DataService) {
// make your DataService available in your scope
$scope.DataService = DataService;
});
This lets you bind models globally to the DataService.
Check out angular-storage A Storage done right for AngularJS. It is great for storing user info/tokens/ any object.
Key Features
Uses localStorage or sessionStorage by default but if it's not available, it uses ngCookies.
Lets you save JS Objects
If you save a Number, you get a Number, not a String
Uses a caching system so that if you already have a value, it won't get it from the store again.
https://github.com/auth0/angular-storage
There is lot of ways of to achieve this
1) Use $rootscope like you use $scope like
$rootscope.userName = ""
Inject the $rootscope dependency in the controller where you want to show it and create an object name Employee and fill it with $rootscope.
2) use constant like
module.constant("userData", data);
Inject the userData dependency in the controller where you want to show it and create an object name Employee and fill it with userData.
3) You can use service/factory and save the data in localstorage/sessionstorage
to transfer data between pages, you can use stateParams:
in the routes file:
$stateProvider
.state('employeeMasterState', {
url: '/employeeMasterUrl/:employeeData',
templateUrl: 'info/employeeMaster.tpl.html',
controller: 'employeeMasterCtrl',
controllerAs: 'employeeMasterCtrlAs'
});
js:
$scope.GetData = function () {
debugger;
var data = { UserName: $scope.username, Password: $scope.password };
$http.post("api/Test/CheckUsername", data)
.success(function (data, status, headers, config) {
if (data != "") {
this.state.go('employeeMasterState',{employeeData:data});
}
else {
alert("Invalid Credientials");
}
});
}
in the next page js:
constructor($scope, $statePArams){
$scope.empData = $stateParams.data;
}
You can create a service or a factory to share data between webpages. Here is the documentation

Expected response to contain an object but got an array

I get this error, I found many thread with the same message, but it never seems to match my case, and I didn't manager to solve it.
Basivally, everything was ok until I tried to make 1 form for create and update a 'Car' object.
Here is a presentation of my app (build from this template: https://github.com/linnovate/mean):
/public/js/config.js:
[...]
.state('edit car', {
url: '/cars/:carId/edit',
templateUrl: 'views/cars/edit.html'
})
.state('create car', {
url: '/cars/create',
templateUrl: 'views/cars/edit.html'
})
/public/js/services/mycars.js (don't really know what services are used for...):
//Cars service used for car REST endpoint
angular.module('mean.mycars').factory('Cars', ['$resource', function($resource) {
return $resource('cars/:carId', {
carId: '#_id'
}, {
update: {
method: 'PUT'
}
});
}]);
public/js/controllers/mycars.js:
angular.module('mean.mycars').controller('MyCarsController', ['$scope', '$http', '$stateParams', '$location', 'Global', 'Cars',
function ($scope, $http, $stateParams, $location, Global, Cars) {
$scope.findOneOrCreate = function () {
// create a new car
var car = new Cars({
id : null,
marque: this.marque,
modele: this.modele,
desc: this.desc
});
// put new car in scope
$scope.car = car;
// if there is a param, search for the car (mode update)
if ($stateParams.carId !== null){
Cars.get({
carId: $stateParams.carId
}, function(carTmp) {
// put the result in scope
$scope.car = carTmp;
});
}
};
$scope.createOrUpdate = function () {
var car = $scope.car;
if (car.id !== null) {
// update
if (!car.updated) {
car.updated = [];
}
car.updated.push(new Date().getTime());
car.$update(function () {
$location.path('cars/' + car._id);
});
}
else {
//Create
car.$save(function (response) {
$location.path('cars/' + response._id);
});
}
};
And finally my view: edit.html:
<section data-ng-controller="MyCarsController" data-ng-init="findOneOrCreate()">
<form class="form-horizontal col-md-6" role="form" data-ng-submit="createOrUpdate()">
<div class="form-group">
<label for="title" class="col-md-2 control-label">Title</label>
<div class="col-md-10">
<input type="text" class="form-control" data-ng-model="car.modele" id="title" placeholder="Title" required>
</div>
</div>
<div class="form-group">
<label for="content" class="col-md-2 control-label">Content</label>
<div class="col-md-10">
<textarea data-ng-model="car.marque" id="content" cols="30" rows="10" placeholder="Content" class="form-control" required></textarea>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="submit" class="btn btn-default">Submit</button>
</div>
</div>
</form>
</section>
Edit to add infos:
The web Services are supposed to return only one car (but not sure if they do), here they are:
exports.car = function(req, res, next, id) {
Car.load(id, function(err, car) {
if (err) return next(err);
if (!car) return next(new Error('Failed to load car ' + id));
req.car = car;
next();
});
};
exports.create = function(req, res) {
var car = new Car(req.body);
car.user = req.user;
car.save(function(err) {
if (err) {
return res.send('users/signup', {
errors: err.errors,
car: car
});
} else {
res.jsonp(car);
}
});
};
exports.update = function(req, res) {
var car = req.car;
car = _.extend(car, req.body);
car.save(function(err) {
if (err) {
return res.send('users/signup', {
errors: err.errors,
car: car
});
} else {
res.jsonp(car);
}
});
};
Error message appears when I go to /cars/create, not when I go to /cars/:carsId/edit:
Error: [$resource:badcfg] Error in resource configuration. Expected response to contain an object but got an array
http://errors.angularjs.org/1.2.15/$resource/badcfg?p0=object&p1=array
Is your web service returning an array? The get method expects only one object to be returned, and the same with your PUT request if you're returning something. If you're expecting multiple you will need to specify isArray: true in your service method in mycars.js. See example here: http://docs.angularjs.org/api/ngResource/service/$resource

Categories

Resources