Why is angular-promise-tracker not working for me? - javascript

I've installed angular-promise-tracker and I think I'm close to getting it working. The problem I'm having is that the "loading" text isn't showing. The data is fetched and does show when outputting it to the console.
So it appears that ng-show="loadingTracker.active()" isn't working. I can't see what I'm doing wrong with this.
Any help with this would be sincerely appreciated - as always :)
Here's my code:
HTML
<button ng-controller="weatherCtrl"
ng-model="hotel"
class="btn btn-default"
ng-click="loadWeather(hotel, $index)">
{{buttonText}} more</button>
<div collapse="isCollapsed">
<div class="well well-lg more-detail">
{{hotel.Description}}
<br /><br />
<div>
<div class="my-super-awesome-loading-box"
ng-show="loadingTracker.active()">
Loading..
</div>
</div>
</div>
</div>
JS
.controller('weatherCtrl', function ($scope, weather, $timeout, promiseTracker){
$scope.loadingTracker = promiseTracker();
$scope.buttonText= 'Load'
$scope.loadedHotelDetails=[];
$scope.loadWeather = function(hotel, index) {
// console.log('loadWeather')
weather.get({tracker: $scope.loadingTracker}, function (data){
console.log(data)
$scope.loadedHotelDetails.push(index)
})
})
angular.module('weather', [])
.factory('weather', function($http) {
var weather = {};
weather.get = function(params, callback) {
$http.get('/php/weather.php', {params: {tracker: params.tracker, page: params.page}}).success(function(data) {
callback(data);
});
};
return weather;
});

I've never used this module, but from the examples on github, I think you're supposed to call it like this in weather:
weather.get = function(params, callback) {
$http.get('/php/weather.php', {tracker: params.tracker, page: params.page}).success(function(data) {
callback(data);
});
};

Got it sorted, this is the code I needed:
.factory('weather', function($http) {
var weather = {};
weather.get = function(params) {
return $http.get('/php/weather.php', {tracker: params.tracker, page: params.page});
};
return weather;
});

Related

AngularJS Error: Cannot set property 'UserData' of null

I run the following AngularJS code from a partial page:
$scope.$parent.UserData = {};
$http.get('http://.../GetUserData/').
then(function (result) {
$scope.$parent.UserData = result.data;
}, function errorCallback(error) {
console.log(error);
});
I know that $scope.$parent is not null and I know that result.data returns an object with multiple properties. Not sure why I am getting this error since $scope.$parent is not null
The above partial page is displayed in ui-view on index page. Here is html from index page:
<body ng-controller="BaseCtrl">
<nav>
</nav>
<div class="" ui-view>
//partial pages displayed here
</div>
<!-- Modal Structure -->
<div id="modal1" class="modal">
<div class="modal-content">
<h4>Heading</h4>
<div class="row">
<table>
<tr>
<td>ID:</td>
<td>{{UserData.ID}}</td>
</tr>
<tr>
<td>Person name:</td>
<td>{{UserData.Name}}</td>
</tr>
</table>
</div>
</div>
<div class="modal-footer">
<button ng-click="closeModal()" class="modal-action modal-close waves-effect waves-green btn-flat">Close</button>
</div>
</div>
</body>
I think you have not defined $scope.$parent. So define it first.
$scope.$parent = {};
$scope.$parent.UserData = {};
$http.get('http://.../GetUserData/').
then(function (result) {
$scope.$parent.UserData = result.data;
}, function errorCallback(error) {
console.log(error);
});
Optimal syntax for object of objects.
$scope.$parent = {UserData:{}};
could please try this
$http.get('http://.../GetUserData/').
then(function (result) {
$scope.$parent.UserData = {};
$scope.$parent.UserData = result.data;
}, function errorCallback(error) {
console.log(error);
});
After a while of trying out different things I finally came up with the solution. Here is what worked for me:
$scope.$parent.UserDataColl = [];
$http.get('http://.../GetUserData/').
then(function (result) {
$scope.UserDataColl.push(result.data);
}, function errorCallback(error) {
console.log(error);
});

How to make saved object immediately appear in a ng-repeat?

JS:
$scope.addPano = function () {
var Pano = AV.Object.extend("Panorama"),
pano = new Pano()
var json = {
'name': 'test3',
'index': 0,
'Type': 'real',
'version': 0,
'buildingCode': $scope.buildingId
}
pano.save(json, {
success: function(object) {
console.log('PANO: ', object)
$scope.building.pano.push(json)
$scope.$digest()
},
error: function(object, error) {
console.log('Failed to create new object, with error message: ' + error.message);
}
})
}
HTML:
<div ng-repeat="pano in building.pano">
<p><strong>{{pano.name}}</strong></p>
<div ng-repeat="panodata in pano.panoData">
<p>{{panodata.name}}</p>
</div> <a class="btn btn-default" href="javascript:;" ng-click="addPanodata(pano.objectId)">Add panodata</a> </div> <a class="btn btn-default btn-lg" href="javascript:;" ng-click="addPano()">Add pano</a>
</div>
Right now the only way to make it appear is with:
$scope.building.pano.push(json)
$scope.$digest()
I thought Angular did this automatically?
I think you can try this type But In your code either you reload data after save method calling successfully then you can easily appear easily..
function myctrl($scope){
$scope.data =[{name:'abc'}];
$scope.pushdata = function(name){
$scope.data.push({name});
$scope.name ='';
}
}
<html ng-app=''>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
</head>
<body ng-controller='myctrl'>
<input type='text' name='name' ng-model='name'/>
<button name='clickme' type=submit ng-click='pushdata(name)'>save</button>
<div ng-repeat='obj in data'>
{{obj.name}}
</div>
</body>
</html>
The official way to do this is to write your pano service to support angular. So where you call the success callback in the service:
.factory('pano', function() {
return {
save: function(x, options) {
setTimeout(function() {
options.success(123);
}, 1000);
}
};
});
You should wrap it in a $scope.$apply so angular has an opportunity to run dirty-checking:
.factory('pano', function($rootScope) {
return {
save: function(x, options) {
setTimeout(function() {
$rootScope.$apply(function() {
options.success(123);
});
}, 1000);
}
};
});
The same applies for the error handling callback.
Note: The builtin angular services, like $http, $q, $timeout do this automatically.

Updating ng-show from within .then()

I have a loader that I show while an async service call is completed, and simply want to hide the loader when complete. Here is my controller:
app.controller('DataController',
function($scope, DataService) {
// UI state
$scope.loading = true;
DataService.getData({ "count": 10 }).then(function(data) {
$scope.data = data;
// UI state
$scope.loading = false; // does not update ng-view
$scope.$apply(function() { // generates error
$scope.loading = false;
});
});
});
And the view:
<div ng-controller="DataController">
<div id="container">
<div>
{{ loading }}
</div>
<div class="spinner large" ng-show="loading"></div>
<div class="data-container" ng-show="!loading">
...
</div>
</div>
</div>
Note the the {{ loading }} value gets updated properly in the view. Using the wrapping $scope.$apply() call resulted in an error:
Error: [$rootScope:inprog]
UPDATE
As this might be promise-related, here's the promise generating getData() method from the DataService factory:
getData: function(params) {
var deferred = $q.defer();
APIService.data(params).then(function(data) {
deferred.resolve(data);
});
return deferred.promise;
}
And the last piece, the APIService.data() method:
data: function(params) {
var deferred = $q.defer();
$resource(endpoint + '/data/feed', {}, {
'query': {
method: 'POST',
headers: headers
}
}).query(params).$promise.then(function(data) {
deferred.resolve(data);
});
return deferred.promise;
}
I would solve this by binding the show/hide directive to the data-property in the controller. It will be the same as false if the data is undefined.
<div class="spinner large" ng-hide="data"></div>
<div class="data-container" ng-show="data">
Try to use
$scope.$evalAsync(function() {
$scope.loading = false;
});
Found the issue - as this is in a Chrome Extension, I needed to include the Angular CSS CSP file, which includes the ng-hide class definition. Including that file resulted in the code working as expected. Thanks everyone for the help. More info:
https://docs.angularjs.org/api/ng/directive/ngCsp

How to write an angularJs Controller to GET Rest Data from Parse.com

See solution below:
I'm trying to connect to a Parse.com Rest backend and display data from object values.
HTML (I put several angular calls to be sure to catch output):
<div ng-controller="MyController">
<p>{{item}}<p>
<p>{{items}}<p>
<p>{{item.firstName}}<p>
<p>{{data}}<p>
</div>
JAVASCRIPT rest:
function MyController($scope, $http) {
$scope.items = [];
$scope.getItems = function() {
$http({method : 'GET',url : 'https://api.parse.com/1/classes/Professional/id', headers: { 'X-Parse-Application-Id':'XXXX', 'X-Parse-REST-API-Key':'YYYY'}})
.success(function(data, status) {
$scope.items = data;
})
.error(function(data, status) {
alert("Error");
});
};
}
This won't work, it does strictly nothing, not even a message in the console.
I know the rest call got the correct credential, as I'm able to get object content returned when I test it with a rest tester program. Maybe the URL should not be absolute ?
Any clue is very welcome, i've spent DAYS on that.
SOLUTION:
Thanks to the help of people answering this thread, I was able to find the solution to this problem so I just wanted to contribute back:
Get Json object data from Parse.com backend, pass it authentification parameters:
function MyController($scope, $http) {
$scope.items = [];
$scope.getItems = function() {
$http({method : 'GET',url : 'https://api.parse.com/1/classes/Professional', headers: { 'X-Parse-Application-Id':'XXX', 'X-Parse-REST-API-Key':'YYY'}})
.success(function(data, status) {
$scope.items = data;
})
.error(function(data, status) {
alert("Error");
});
};
Notice that ' ' necessary arround header key object values. Those ' ' are not necessary around method and url keys.
Template that list all 'firstName' of each object:
<div ng-controller="MyController" ng-init="getItems()">
<ul>
<li ng-repeat="item in items.results"> {{item.firstName}} </li>
</ul>
</div>
Notice: "item in items.results". "results" is necessary because the return value is a JSON object that contains a results field with a JSON array that lists the objects. This could save you some headache.
Also notice "ng-init": if you don't put that, or any other form of call to the getItem(),then nothing will happen and you will be returned no error.
That was my first try of Angularjs, and i'm already in love ^^.
Based in your request the controller should be:
HTML
<div ng-controller="MyController">
<button type="button" ng-click="getItems()">Get Items</button>
<ul>
<li ng-repeat="item in items"> item.firstName </li>
</ul>
</div>
JS
function MyController($scope, $http) {
$scope.items = []
$scope.getItems = function() {
$http({method : 'GET',url : 'https://api.parse.com/1/classes/Users', headers: { 'X-Parse-Application-Id':'XXXXXXXXXXXXX', 'X-Parse-REST-API-Key':'YYYYYYYYYYYYY'}})
.success(function(data, status) {
$scope.items = data;
})
.error(function(data, status) {
alert("Error");
})
}
}
Just a little update to the newer versions of Angular (using .then since version 1.5):
myApp.controller('MyController', function($scope, $http) {
$scope.items = []
$http({
method: 'GET',
url: 'https://api.parse.com/1/classes/Users',
headers: {'X-Parse-Application-Id':'XXXXXXXXXXXXX', 'X-Parse-REST-API-Key':'YYYYYYYYYYYYY'}
})
.then(function successCallback(response) {
alert("Succesfully connected to the API");
$scope.items = data;
}, function errorCallback(response) {
alert("Error connecting to API");
});
});
var app = angular.module("app",[]);
app.controller("postcontroller", function($scope, $http){
$scope.getAllProjects = function() {
var url = 'https://reqres.in/api/products';
$http.get(url).then(
function(response) {
$scope.projects = response.data.data;
},
function error(response) {
$scope.postResultMessage = "Error with status: "
+ response.statusText;
});
}
$scope.getAllProjects();
});
<div ng-app="app">
<div ng-controller="postcontroller">
<div class="panel-body">
<div class="form-group">
<label class="control-label col-sm-2" for="project">Project:</label>
<div class="col-sm-5">
<select id="projectSelector" class="form-control">
<option id="id" ng-repeat="project in projects"
value="{{project.id}}">{{project.name}}</option>
</select>
</div>
</div>
</div>
</div>
</div>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js"></script>

Angular ui grid how to show a loader

I'm wondering how to show a simple loader before data was loaded.
I'm using ng-grid-1.3.2
I'm googling but I didn't find any example.
Bye
like Maxim Shoustin suggested you can use the angularjs-spinner from Jim Lavin which uses (deprecated) Response Interceptors.
I think it's explained best here :
http://codingsmackdown.tv/blog/2013/04/20/using-response-interceptors-to-show-and-hide-a-loading-widget-redux/
In a nutshell, in his first solution, what you have to do for your ng-grid app is:
1) Add the loading gif to your html (for loading gif look here)
<div id="loadingWidget" class="row-fluid ui-corner-all" style="padding: 0 .7em;" loading-widget >
<div class="loadingContent">
<p>
<img alt="Loading Content" src="images/ajax-loader.gif" /> Loading
</p>
</div>
</div>
2) In your code as soon as you have declared your app level module add the Response Interceptors for http requests to the configuration block
var app = angular.module('myCoolGridApp', ['ngGrid']);
app.constant('_START_REQUEST_', '_START_REQUEST_');
app.constant('_END_REQUEST_', '_END_REQUEST_');
app.config(['$httpProvider', '_START_REQUEST_', '_END_REQUEST_', function ($httpProvider, _START_REQUEST_, _END_REQUEST_) {
var $http,
interceptor = /* see extra details on codingsmackdown.tv */
$httpProvider.responseInterceptors.push(interceptor);
}
3) and then add your loadingWidget directive
app.directive('loadingWidget', ['_START_REQUEST_', '_END_REQUEST_', function (_START_REQUEST_, _END_REQUEST_) {
return {
restrict: "A",
link: function (scope, element) {
element.hide();
scope.$on(_START_REQUEST_, function () {element.show();});
scope.$on(_END_REQUEST_, function () {element.hide();});
}
};
}]);
See more details at codingsmackdown
I had the same question as you.
I find this nice tutorial about it: http://brianhann.com/ui-grid-the-easiest-customization-youll-ever-write/
He use vm.loading = true while fetching data from server and changed to false after complete.
var app = angular.module('app', ['ngTouch', 'ui.grid']);
app.controller('MainCtrl', ['$http', '$timeout', function ($http, $timeout) {
var vm = this;
vm.reset = reset;
vm.noData = noData;
vm.gridOptions = {
columnDefs: [
{ field: 'name' },
{ field: 'age' }
]
};
reset();
////////////
// Initialize our data source
function init() {
$http.get('data.json')
.success(function (data) {
vm.gridOptions.data = data;
})
.finally(function () {
vm.loading = false;
});
}
// Reset the data source in a timeout so we can see the loading message
function reset() {
vm.loading = true;
vm.gridOptions.data = [];
$timeout(function () {
init();
}, 1000);
}
function noData() {
vm.gridOptions.data = [];
}
}]);
In the HTML, he uses ng-hide to show/hide the spinner based on values of gridOptions.data and vm.loading:
<div id="grid1" ui-grid="vm.gridOptions" class="grid">
<div class="grid-msg-overlay" ng-hide="!vm.loading">
<div class="msg">
<span>
Loading Data...
<i class="fa fa-spinner fa-spin"></i>
</span>
</div>
</div>
<div class="grid-msg-overlay" ng-hide="vm.loading || vm.gridOptions.data.length">
<div class="msg">
<span>No Data</span>
</div>
</div>
</div>
Here is the Plunker of the final version shown.
You have angularjs-spinner, see GitHub sources
I also needed a similar behavior and I came across this answer but I needed to show something inside the grid itself so here is something I put together. My idea is that I change the gridOptions on the fly and show a loader as a row inside the grid.
loaderOptions = {
"columnDefs": [{
"name": "",
"field": "loading",
"enableColumnMenu": false,
"cellTemplate": '<div style="width:90px; margin:auto;"><span class="glyphicon glyphicon-refresh glyphicon-refresh-animate"></span> Loading...</div>'
}],
"data": [{
"loading": ""
}]
};
Simply,by adding this code in your html part:
<img alt="loading..." src='images/ajax-loader.gif")' /> loading message...
and the following code in your app.controller script:
$http.get(yourdataUrl)
.then(function (response) {
$scope.records = response.data;
$("#loadingWidget").hide();
});
it works fine for me!
The HTML code-sample
<img ng-show="loading" src="~/img/loding.jpg" />
<div class="ngtyle" ng-grid="myGridView"></div>
The AngularJs code-sample
var app = angular.module('App', ['ngGrid']);
app.controller('MainCtrl', function ( $scope, myService ) {
$scope.loading = true;
myService.get().then( function ( response ) {
$scope.items = response.data;
})
.finally(function() {
$scope.loading = false;
});
$scope.myGridView = {
data: 'dataList',
columnDefs: 'myDisplayColumns'};
});

Categories