A Better $state.reload for the AngularJS UI-Router
While working on Apigility, several times I ran into an odd issue: after fetching new data via an API and assigning it to a scoped variable, content would flash into existence… and then disappear. Nothing would cause it to display again other than a browser reload of the page.
Setup
I have a page that lists a set of items. When you create an item, you push data to the API, and, when done, the new item should be in that list.
First try: append to list
My first attempt was just appending the data to the list.
service.create(data).then(function (newItem) {
    flash.success = 'Successfully created something';
    /* append new item to list */
    $scope.services.push(newItem);
});
This worked… until you left that screen and returned. At that point, the new item would be gone, even if I coded my ui-router states to force a cache refresh.
Refresh list
My next attempt was to write a routine that would do a cache refresh after creating the new item.
service.create(data).then(function (newItem) {
    flash.success = 'Successfully created something';
    service.fetchAll(var force = true).then(function (services) {
        $scope.services = services;
    });
});
This is when I started noticing the "flash of content" problem. Essentially, immediately after fetching the set of services, you'd see the new item appended… and then it would disappear.
$state.reload()
At this point, I figured I'd use the ui-router to force a refresh, specifically
via $state.reload().
service.create(data).then(function (newItem) {
    flash.success = 'Successfully created something';
    service.fetchAll(var force = true).then(function (services) {
        $scope.services = services;
        $state.reload();
    });
});
I tried both with and without setting the scoped variable. Initially, I thought it was working — but, as it turned out, I missed a case. I tested every single time with at least one item already in the list — and this approach worked. However, when I tried with the list not yet populated, failure once again.
Success: $timeout
Surprisingly, the least intuitive solution ended up working: introducing a delay.
service.create(data).then(function (newItem) {
    flash.success = 'Successfully created something';
    service.fetchAll(var force = true)
        .then(function (services) {
            $scope.services = services;
        }).then(function () {
            return $timeout(function () {
                $state.go('.', {}, { reload: true });
            }, 100);
        });
});
I have a few things to note about this. First, I moved the "reload" into its
own promise. This was done to ensure it doesn't block on the scope assignment.
Second, I introduce a $timeout call. This essentially gives the scope a
chance to populate before the reload triggers. Some examples I saw did a 1ms
timeout; I found in practice that this was not long enough; 100ms was long
enough, and did not introduce a noticeable delay in UI responsiveness. Finally,
you'll note this does not use $state.reload(). This is due to discovering
that part of my problem is a known bug in $state.reload(),
whereby state "resolve" configuration is not honored.
I hope this approach helps others — I've found it to be robust and predictable.