Giter Site home page Giter Site logo

angular-promise-tracker's Introduction

angular-promise-tracker

Version: 2.0

(note to users using version 1.x: upgrading has many breaking changes, see the CHANGELOG.)

Build Status

Small, feature filled library used to easily add spinners or general promise/request tracking to your angular app.

Quick Start

The basic idea: each time we add one or more promises to an instance of a promiseTracker, that instance's active() method will return true until all added promises are resolved. A common use case is showing some sort of loading spinner while some http requests are loading.

Play with this example on plunkr

$ bower install angular-promise-tracker
<body ng-app="myApp" ng-controller="MainCtrl">
  <div class="my-super-awesome-loading-box" ng-show="loadingTracker.active()">
    Loading...
  </div>
  <button ng-click="delaySomething()">Delay Something</button>
  <button ng-click="fetchSomething()">Fetch Something</button>

  <script src="angular.js"></script>
  <script src="promise-tracker.js"></script>

  <!-- optional for $http sugar -->
  <script src="promise-tracker-http-interceptor.js"></script>
</body>
angular.module('myApp', ['ajoslin.promise-tracker'])
.controller('MainCtrl', function($scope, $http, $timeout, promiseTracker) {
  //Create a new tracker
  $scope.loadingTracker = promiseTracker();

  //use `addPromise` to add any old promise to our tracker
  $scope.delaySomething = function() {
    var promise = $timeout(function() {
      alert('Delayed something!');
    }, 1000);
    $scope.loadingTracker.addPromise(promise);
  };

  //use `tracker:` shortcut in $http config to link our http promise to a tracker
  //This shortcut is included in promise-tracker-http-interceptor.js
  $scope.fetchSomething = function(id) {
    return $http.get('/something', {
      tracker: $scope.loadingTracker
    }).then(function(response) {
      alert('Fetched something! ' + response.data);
    });
  };
});

API Documentation

Service promiseTracker

  • tracker promiseTracker([options])

    Creates and returns a new promiseTracker.

    Options can be given as an object, with the following allowed values:

    • activationDelay {Number} - Number of milliseconds that an added promise needs to be pending before this tracker is active.
      • Usage example: You have some http calls that sometimes return too quickly for a loading spinner to look good. You only want to show the tracker if a promise is pending for over 500ms. You put {activationDelay: 500} in options.
    • minDuration {Number} - Minimum number of milliseconds that a tracker will stay active.
      • Usage example: You want a loading spinner to always show up for at least 750ms. You put {minDuration: 750} in options.

    Often you want a global promiseTracker (eg to show a loading screen); one easy way is to put the tracker on your $rootScope:

    app.run(function($rootScope, promiseTracker) {
      $rootScope.loadingTracker = promiseTracker();
    });

Instantiated promiseTracker

Example: var myTracker = promiseTracker({ activationDelay: 500, minDuration: 750 });

  • boolean tracker.active()

    Returns whether this tracker is currently active. That is, whether any of the promises added to/created by this tracker are still pending. Note: if the activationDelay has not elapsed yet, this will return false.

  • boolean tracker.tracking()

    Returns whether this tracker is currently tracking a request. That is, whether any of the promises added to/created by this tracker are still pending. This method has no regard for activationDelay.

  • number tracker.trackingCount()

    The count of promises currently being tracked.

  • promise tracker.addPromise(promise)

    Add any arbitrary promise to tracker. tracker.active() will be true until promise is resolved or rejected.

    • promise {object} - Promise to add

    Usage Example:

    var promise = $timeout(doSomethingCool, 1000);
    myTracker.addPromise(promise);
    console.log(myTracker.active()); // => true
    //1000 milliseconds later...
    console.log(myTracker.active()); // => false
  • promise tracker.createPromise()

    Creates and returns a new deferred object that is tracked by our promiseTracker.

    Usage Example:

    var deferred = myTracker.createPromise()
    console.log(myTracker.active()); // => true
    deferred.resolve();
    console.log(myTracker.active()); // => false
  • void tracker.cancel()

    Causes a tracker to immediately become inactive and stop tracking all current promises.

$http Sugar

Requires promise-tracker-http-interceptor.js

  • Any $http call's config parameter can have a tracker field. Examples:
//Add $http promise to tracker with id 'myTracker'
$http('/banana', { tracker: myPromiseTrackerInstance })
//Add $http promise to both 'tracker1' and 'tracker2'
$http.post('/elephant', {some: 'data'}, { tracker: [myFirstTracker, mySecondTracker] })

More Examples

  • Do something whenever the tracker's active state changes
angular.module('app', ['ajoslin.promise-tracker'])

.factory('myTracker', function (promiseTracker) {
  return promiseTracker();
})

.controller('AppCtrl', function ($rootScope, myTracker) {
  $rootScope.$watch(myTracker.active, function (isActive) {
    //doSomething()
  });
});

Development

  • Install karma & grunt with npm install -g karma grunt-cli to build & test
  • Install local dependencies with bower install && npm install
  • Run grunt to lint, test, build the code, and build the docs site
  • Run grunt dev to watch and re-test on changes

New Versions

License

Public Domain Mark angular-promise-tracker by Andy Joslin is free of known copyright restrictions.

angular-promise-tracker's People

Contributors

0x-r4bbit avatar ajoslin avatar chandan-singh avatar daviesgeek avatar igosuki avatar matmar10 avatar posgarou avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

angular-promise-tracker's Issues

Add a usage example

I needed some time to find out how to react on active() changes. Maybe you can add an example like

angular.module('app', ['ajoslin.promise-tracker'])

.factory('myTracker', function (promiseTracker) {
  return promiseTracker();
})

.controller('AppCtrl', function ($rootScope, myTracker) {
  $rootScope.$watch(myTracker.active, function (isActive) {
    // Do something while the tracker is active
  });
})

;

Minified version of 1.4.2 is broken

There appears to be a syntax error in the minified version of 1.4.2:

SCRIPT1009: Expected '}'
promise-tracker.min.js, line 8 character 3251

Remove Events System

It seems to me the events system is a useless bloat feature: I added it at the start just 'as a thing' (I mean the tracker.on('done', cb) kind of thing).

  1. Takes up more KB, bad for mobile
  2. Almost everything it can do is done well with promise events or a tiny bit more work for the developer
  3. Does anyone actually use the events?

If we remove it, promise-tracker can become a good micro-library that does only what you need.

Write the docs!

If someone wants to help write a part of the docs/guide on the wiki, go for it. Even if it's one word. Or half a word :-)

Broken in AngularJS v1.1.4

not sure if it's me or promiseTracker but after updating to the unstable version of AngularJS I am getting the following:

TypeError: Cannot read property 'tracker' of undefined
    at spinnerResponseInterceptor (promise-tracker-v0.0.1.js:95:39)

Move to 1.1.5 in bower.json?

I've created a component that builds of the promise-tracker (which is great!) but I've used 1.1.5 due to the changing ng-animate syntax. I haven't seen any issues with the promise-tracker in 1.1.5 and I'm guessing you just haven't bothered to update it. Right now my component is ~1.1.5 and promise-tracker is 1.1.4 so bower pukes.

For ref my component is at:
https://github.com/cgross/angular-busy

Feature request: add tracker to entire resource

Hi,

would be cool if we could add a tracker to an entire resource with the result that all resource methods (or only marked ones) will trigger the tracker. Maybe by modifing headers?

angular.module('project', ['ngResource'])
    .config(['$httpProvider', function ($httpProvider) {
        $httpProvider.defaults.headers.tracker = 'myTracker';
    }])
    .factory('Project', ['$resource', function($resource) {
        var Project = $resource('/projects/:id', {},
        {
            update: {
                method: 'PUT',
                tracker: 'exclude'
            }
        });

    // More stuff in here

    return Project;
}]);

http://docs.angularjs.org/api/ng.$http

Pass tracker options along $http interceptor, or at promiseTracker "get" constructor

From the documentation and what I could make sense from the source code, the only time I can pass options to a tracker is if I instantiate it myself.
If I create a tracker using $http interceptor, and later in a controller I recover it to see if it is active, I can't pass activationDelay or minDuration:

// service
$http.get('/url', { tracker: 'url_tracker'}) ...

// controller
$scope.tracker = promiseTracker('url_tracker'); // no options

Possible solutions:

// service
$http.get('/url', { tracker: { name: 'url_tracker', options: options } }) ...

// controller
$scope.tracker = promiseTracker('url_tracker', options);

Error in IE8 when using {tracker: 'api'} inside service

I get the following error in IE8: TypeError: Object doesn't support this property or methodundefined.

Here is my setup: In app.js, I include promiseTracker and create a reference $rootScope.apiTracker = promiseTracker('api');

Then, in my services I include {tracker: 'api'}, for example:

exports.getAll = function() {
    return $http.get(url + 'vendor', {'tracker' : 'api'}).then(function (response) {
        return response.data;
    });
};

This works fine in Chrome, and even IE10. However in older IE8 i get the error as described above.

registering tracker might requre a revision

scenario a face the issue.
http://plnkr.co/edit/XU0tvWsfKcuJPL9oXyCh

has a simple ui router, (I guess same story with ngroute)

with original promise-tracker I get:
Error: Tracker with id "loadingTracker" already exists!

Long story short, when switching from view/controller to another then return back, we face errors because of -reregistering same promises/trackerId.

what's the way it should be done? use the plnkr link to see what I mean.

also I'll create a pull request to show the mods that addresses the issue for me.

p.s. I didn't run the tests from the project.

View active promises

Is it possible to get a list of active promises from a tracker? This would be a nice feature

Some sort of unique promise ID to track with?

First of all, this thing is fantastic! Well done!

I'm using the 'start' event to push message objects into an array that are displayed in an ng-repeat. Then on the 'success' and 'error' events, I'm setting message.cssClass = 'green' or 'red', respectively. The problem is I need some way to know which message in the array to update.

It would be really cool if some unique ID was passed along into all the events to make following them in the event sequence easier.

Or, if you're against that idea, do you have any suggestions on a better way to do this? Right now, in the 'start' event I'm setting my message.id = config.url, but that, of course, isn't guaranteed to be unique. And if I wanted to add plain old promises (not from $http) to my tracker, I wouldn't even have that available...

Conventional Changelogs

To make sure that we get clean commits and are able to generate a full featured changelog automatically, we have to introduce @btford's awesome grunt-conventional-changelog task.

Getting events fired multiple times. What am i doing wrong?

I'm trying to setup the promise tracker in a hierarchical kind of way and running into an issue.

My app has a structure where each controller inherits everything from a parent application_controller. In this application controller, I've added the following method :

$scope.track = function(trackerName, request) {

    var tracker = $scope[trackerName];
    if (!tracker) {
      tracker = promiseTracker(trackerName);
      $scope[trackerName] = tracker;
    }

    tracker.addPromise($q.when(request.$then));

    tracker.on('start', function() { $scope.$broadcast(trackerName + ':start') });
    tracker.on('success', function() { $scope.$broadcast(trackerName + ':success') });
    tracker.on('error', function() { $scope.$broadcast(trackerName + ':error') });
    tracker.on('done', function() { $scope.$broadcast(trackerName + ':done') });
  }

Then, in the child controller, I have:

$scope.meetings = Meeting.query();
$scope.track("meetingsList", $scope.meetings);
$scope.$on("meetingsList:done", function() { console.log("Whoop! - " + new Date()); });

I then have my broadcast listener listening to "meetingsList:done" which simply outputs to the console a simple message.

When I load the page and have it trigger the request, it works as expected, and I see my message appear. If I then navigate to another page and go back, it again works but I get my message twice. Repeating, it appears 3 times, and so on, increasing by 1 each time.

I'm sure that I'm doing something wrong but I'm not entirely sure what that is :(

New Feature: Add a global failure.

It would be nice to show the user that all request are pending too long for unknown reason.

I could show a modal "Something wrong occurred, try again later".

Bower 2.0.0-beta2 is broken

It's feeding the version with stopTimeout when the actual function name is cancelTimeout; looks like the tag got attached to beta1 accidentally.

Any chance you could rev to beta3 so I can update my deps without having to use #master ? ;P

Cheers

Broken demos

Your plunkers still point to a promise-tracker.js file that doesn't exist :)

Tracker for rootScope

Hi,

This is in my base layout

<div ng-show="tracker.active()" class="global-loader">Loading...</div>

It should indicate that there is a request/background process in progress. I don't want to have many trackers like you describe it for your pizza tracker, but just one single tracker that shows loading for any kind of http request in my application.

My approach was to have

$rootScope.tracker = promiseTracker('tracker');

in my main controller. I tried to use it in a module like this

angular.module('AuthService', []).factory('Auth', function($http){

    var config = {
        headers: {
            'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8',
            'X-Requested-With': 'XMLHttpRequest',
            'tracker' : 'tracker'
        }
    }

    return {
        login: function(user, success, error) {
            $http.post('/login', user, config).success(success).error(error);
        },
        logout: function(success, error) {
            $http.post('/logout').success(success).error(error);
        }
    };
});

However this does not work, no error and no loading message displayed. Any ideas how to use a tracker on root scope and in module?

Error when using with angularjs 1.3.0-rc.3

Thanks for the promise tracker!

I have been using it with angularjs 1.3.0-beta.14 but when I upgraded it to 1.3.0-rc.3 I see the error below when I call loadingTracker.addPromise(deferred.promise) where loadingTracker is defined on $rootScope:

Uncaught TypeError: Cannot read property '$$state' of undefined 

Promise.then 
PromiseTracker.self.addPromise 

This actual error occurs inside Promise:

screen shot 2014-09-25 at 7 03 01 am

infinite loop

By adding this to my html, it results in an infinite loop. I am not sure it is an angular bug or promise tracker bug.

<div class="loading" ng-show="loadingTracker.active()">
</div>

.controller('MainController', function($scope, promiseTracker){

$scope.loadingTracker = promiseTracker();
})

Feature Request: Add multiple trackers to a request

Use Case:

I have a service that makes multiple calls to the server through $http.get
All these calls are related in the sense that they gather different info from a user
On my UI, I have multiple widgets, where each calls are "linked" to a widget (on a 1:1 basis).

I'd like to have 1 tracker for all request (to easily know when all are done), and one tracker per requests, to know when 1 particular widget is done loading;

Proposed:

$http.get('url', {tracker: ['profileTracker', 'demographicsTracker']};

I realize there would be a way to use $q.all to achieve the same functionality, but I think it might be handy to have some "shortcut" built directly in the promiseTracker lib.

Great work by the way!

Support passing the tracker object to $http

I was wondering whether we could somehow get rid of using string ids all over the place with promise tracker and use references to the actual tracker objects instead. Like

//Create / get our tracker with unique ID
  $scope.loadingTracker = promiseTracker.register();

  //use `tracker:` shortcut in $http config to link our http promise to a tracker
  $scope.fetchSomething = function(id) {
    return $http.get('http://httpbin.org/delay/2', {
      tracker: $scope.loadingTracker
    }).then(function(response) {
      alert('Fetched something!\n' + JSON.stringify(response.data, null, 2));
    });
  };

Is there any technical reason why we have to use string ids at the moment?

Show loading for angular resource rest service

Hi,

I have a rest service that looks like this

angular.module('TicketService', ['ngResource']).factory('Ticket', ['$resource',      function($resource){
var Ticket = $resource('/api/tickets/:id1/:action/:id2', //add param to the url
{
    id1:'@id'
}, 

{ 
    list: {
        method: 'GET'
    },
    close: {
        method: 'PATCH',
        params:{
            action:"close",
            id1:"@id"
        }
    },
    open: {
        method: 'PATCH',
        params:{
            action:"open",
            id1:"@id"
        }
    }
}); 

return Ticket;
}]); 

and I query for tickts like this

$scope.tickets = Ticket.query();

How would I throw a promiseTracker on a rest call?

publish to npm

Hey, can we publish this repo to npm. id like to pull it into my project as part of my ci chain

Parse error: additional + for function expression where none is provided

Note: I did not grunt build this myself, I installed the package from bower and then used a script tag to pull in /vendor/angular-promise-tracker/promise-tracker.js.

From the final line of the compiled source provided: /promise-tracker.js

+}());

The + needs a function to "express" after it, which there is none. This causes a parser error in PhantomJS.

From the 8th line of the compiled source:

+angular.module('ajoslin.promise-tracker', []);

This is also entirely unnecessary.

maxDuration callback

It would be nice to have a maxDuration callback. E.g. when maxDuration is reached, e.g. 30 seconds I would like to show a message that something went wrong...

Update bower deps

First, rename components.json to bower.json
Second, move angular-mocks to devDependencies, since it is not needed in client projects.

Allow manually pushing to the http interceptor list

I have usecase where I want to transform the responseError in such a way that the config property is removed from the response. The clean sollution would be to add the your http-interceptor at last, but cause of the inline definition of the interceptor it is hard to do that. It would be nice if I can add the interceptor manually to the $http interceptor list.

Promise 'done' event fired immediately

Me again :P

I've run into another issue. When I add my promise to the tracker, the tracker is firing the 'done' event immediately. As a result I can't use the 'tracker.active()' method for anything as it's always false.

I'm adding my promise via

tracker.addPromise($q.when(request.$then));

As you explain in a previous issue.

In my Rails controller, I am intentionally pausing the request for 3 seconds to ensure that the ajax request isn't completing, however even with this pause, the tracker is still firing the done event instantly.

Any ideas? I'm pretty stumped with this one :(

Feature Request: Delay option

It would be nice to have a way to tell the tracker to not be active until some time in the future. This would prevent the UI tracker element from displaying for actions that happen quickly.

Is there a way to clear all tracked promises?

I am using the promise tracker to show a spinner as I load several pieces of data. I would like a way to clear the promise tracker if the user navigates away or cancels an action.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.