Delay / div directive until the scope value is available

I have a custom directive for soundcloud that requires a soundcloud url. The soundcloud URL is retrieved from the database through the $ http service, however, a div is loaded for the soundcloud attribute and the soundcloud url value is required before it is determined.

I mean the code, https://github.com/jxnblk/plangular/blob/master/src/plangular.js * I have not developed this

This is my HTML code:

<div plangular="{{soundcloud}}"> <button ng-click="playPause()">Play/Pause</button> <progress ng-value="currentTime / duration || 0"> {{ currentTime / duration || 0 }} </progress> </div> 

And this is the Angular Code:

 displaySong.controller('song', ['$scope', '$http', 'fetchSong', function($scope, $http, fetchSong) { $scope.songID $scope.songName; //Controller properties $scope.songPromise; //The song promise for fetching $scope.init = function(songID, userID) { $scope.songID = songID; $scope.userID = userID; $scope.songPromise = $http({ method: "post", url: fetchSong, data: { song_id: $scope.songID }, headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }).then(function(successResponse) { console.log('Successfully fetched song'); console.log(successResponse); var song = successResponse.data; $scope.songID = song.song_id; $scope.songName = song.song_name; $scope.songType = song.song_type; $scope.songEmbed = song.song_embed; $scope.soundcloud = song.song_embed; }, function(errorResponse) { console.log('Error fetching'); $scope.songID = null; }); }; }]); 

I know this is an asynchronous character issue, because when I add this line at the beginning of my song controller:

 $scope.soundcloud = "https://soundcloud.com/jshigley/shine"; 

It works great. I also noticed that when I spam the play / pause button that appears from the directive, I get several console errors "HTTP 404 Not Found", which makes me believe that trying to find the track undefined URL

Since this is a div directive, not a function call, I cannot use promises, for example, chaining a then to my scope $ scope.songPromise. I was thinking of putting it in the controller, and the controller should do something like $ timeout within 5 seconds, but I don't think this delays the execution of the DOM.

The soundcloud url eventually loads, but it remains undefined in the eyes of the plangular directive (in fact, I came across many of these problems with poor loading time of the area and directives). Any Angular wizards wanting to teach me how to tame the asynchronous nature of AngularJS?

+5
source share
2 answers

You can use $ watch in the user directive to watch when URL attributes are changed. IN

  link: function(scope, el, attr) { 

change

 if (src) { resolve({ url: src, client_id: client_id }, function(err, res) { if (err) { console.error(err); } scope.$apply(function() { scope.track = createSrc(res); if (Array.isArray(res)) { scope.tracks = res.map(function(track) { return createSrc(track); }); } else if (res.tracks) { scope.playlist = res; scope.tracks = res.tracks.map(function(track) { return createSrc(track); }); } }); }); } 

to

  scope.$watch('attr.plangular', function(newVal) { resolve({ url: attr.plangular, client_id: client_id }, function(err, res) { if (err) { console.error(err); } scope.$apply(function() { scope.track = createSrc(res); if (Array.isArray(res)) { scope.tracks = res.map(function(track) { return createSrc(track); }); } else if (res.tracks) { scope.playlist = res; scope.tracks = res.tracks.map(function(track) { return createSrc(track); }); } }); }); }, true); 

If you don't want to change the directive, you can use ng-if to load this plangular div only when getting the url.

 <div plangular="{{soundcloud}}" ng-if="haveurl"> 

and in angular code:

 }).then(function(successResponse) { console.log('Successfully fetched song'); console.log(successResponse); $scope.haveurl = true; 
+2
source

Try using ng-show to only display the div once your $ http request is complete.

 <div ng-show="httpRequestComplete" plangular="{{soundcloud}}"> <button ng-click="playPause()">Play/Pause</button> <progress ng-value="currentTime / duration || 0"> {{ currentTime / duration || 0 }} </progress> </div> displaySong.controller('song', ['$scope', '$q', '$http', 'fetchSong', function($scope, $http, fetchSong) { /* add $q promise library */ $scope.songID $scope.songName; var httpRequest = function() { var deferred = $q.defer(); $http({ method: "post", url: fetchSong, data: { song_id: $scope.songID }, headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }).success(function(successResponse) { deferred.resolve({response: successResponse}); console.log('Successfully fetched song', successResponse); var song = successResponse.data; $scope.songID = song.song_id; $scope.songName = song.song_name; $scope.songType = song.song_type; $scope.songEmbed = song.song_embed; $scope.soundcloud = song.song_embed; }).error(function(error) { console.log(error); }); return deferred.promise; }; httpRequest().then(function(response) { $scope.httpRequestComplete = true; console.log('div will show'); }; }]); 

I would do something like this that delays the div showing until httpRequestComplete = true or until your promise is fulfilled ($ q). This ensures that your div not loaded until you get the available information.

0
source

All Articles