In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-29 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
How to use services to complete the application development of audio player, in view of this problem, this article introduces the corresponding analysis and answer in detail, hoping to help more partners who want to solve this problem to find a more simple and feasible method.
Let's talk about services, organize our code and finish our audio player application.
Through this entire series of tutorials, we will develop an audio player broadcast by NPR (National Public Radio), which can display the latest stories on Morning Edition programs and play them in our browsers. The finished version of Demo can be seen here.
So far, we have focused on how to bind views to $scope and how to manage data with controller, from a memory and efficiency point of view, controllers is instantiated only when needed and discarded when not needed, which means that every time we use route to jump or reload a view, the current controller will be destroyed.
Services allows us to save data throughout the life cycle of the application and to share data between controllers.
Part VI: Services
Services is a singleton, that is, in an application, each Serice object will only be instantiated once (with $injector service). It is mainly responsible for providing an interface to put together the methods needed by a specific function. Let's take the $http Service seen in the previous chapter as an example, which provides a method to access the XMLHttpRequest object of the underlying browser. Compared to calling the underlying XMLHttpRequest object, $http API is quite easy to use.
Angular has a lot of built-in services for our daily use, which are very useful for building our own Services in complex applications.
AngularJS allows us to easily create our own services, just register the service, once registered, the Angular compiler can find and load it as a dependency for the program runtime to use
The most common way to create is to use angular.module API's factory mode
Angular.module ('myApp.services', []) .factory (' githubService', function () {var serviceInstance = {}; / / our first service return serviceInstance;})
Of course, we can also use the built-in $provide service to create a service.
The service doesn't do anything practical, but it shows us how to define a service. To create a service is to simply return a function that returns an object. This object is created when the application instance is created (remember, this object is a singleton object)
We can deal with specific requirements in this singleton object that runs through the application, and in the above example, we started to create a GitHub service
Next, let's add some meaningful code to call GitHub's API:
Angular.module ('myApp.services', []) .factory (' githubService', ['$http', function ($http) {var doRequest = function (username, path) {return $http ({method: 'JSONP', url:' https://api.github.com/users/' + username +'/'+ path +'? callback=JSON_CALLBACK'}) } return {events: function (username) {return doRequest (username, 'events');},};}])
We have created a GitHub Service,events with only one method that can get the latest GitHub event for a given GitHub user, in order to add this service to our controller. We create a controller and load (or inject) githubService as runtime dependencies, and we pass the name of service as an argument to the controller function (using square brackets [])
App.controller ('ServiceController', [' $scope', 'githubService', function ($scope, githubService) {}])
Please note that this dependency injection approach is safe for js compression, which we will discuss in more detail in later chapters.
Once our githubService is injected into our ServiceController, we can use githubService like any other service (the $http service we mentioned earlier).
Let's modify our sample code to call GitHub API for the GitHub user name given in our view, and as we saw in the third chapter of data binding, we bind the username property to the view
Type in a GitHub username {{events}}
Now we can monitor the $scope.username property, based on bidirectional data binding, and as long as we modify the view, the corresponding model data will also be modified.
App.controller ('ServiceController', [' $scope', 'githubService', function ($scope, githubService) {/ / Watch for changes on the username property. / / If there is a change, run the function $scope.$watch ('username', function (newUsername) {/ / uses the $http service to call the GitHub API / / and returns the resulting promise githubService.events (newUsername). Function (data, status) Headers) {/ / the success function wraps the response in data / / so we need to call data.data to fetch the raw data $scope.events = data.data }));}])
Because $http promise is returned (as we did in the previous chapter), we can call the .success method as if we had called $http service directly.
(sample screenshot, please go to the original text for testing)
In this example, we notice that there is some delay before the content of the input box is changed. If we do not set the delay, then we will call GitHub API for each character of the input box, which is not what we want. We can use the built-in $timeout service to achieve this delay.
If we want to use the $timeout service, we can simply inject it into our githubService
App.controller ('ServiceController', [' $scope','$timeout', 'githubService', function ($scope, $timeout, githubService) {}])
Note that we have to follow the Angular services dependency injection specification: custom service is written after the built-in Angular services, and there is no order between custom service.
We can use the $timeout service now, and in this case, $timeout service will not send any network requests if the change interval of the contents of the input box is not more than 350ms. In other words, if you type on the keyboard for more than 350ms, we assume that the user has finished typing and we can start sending requests to GitHub.
App.controller ('ServiceController', [' $scope','$timeout', 'githubService', function ($scope, $timeout, githubService) {/ / The same example as above, plus the $timeout service var timeout; $scope.$watch (' username', function (newVal) {if (newVal) {if (timeout) $timeout.cancel (timeout)) Timeout = $timeout (function () {githubService.events (newVal) .success (function (data, status) {$scope.events = data.data;});}, 350);});}])
From the beginning of this application, we only see how Services integrates simple functions, and Services can also share data among multiple controllers. For example, if our application has a settings page for users to set up their GitHub username, then we need to share username with other controllers.
In the final chapter of this series, we will discuss routing and how to jump through multiple pages.
In order to share username between controllers, we need to store username in service. Remember, Service exists throughout the life cycle of an application, so you can store username securely here.
Angular.module ('myApp.services', []) .factory (' githubService', ['$http', function ($http) {var githubUsername; var doRequest = function (path) {return $http ({method: 'JSONP', url:' https://api.github.com/users/' + githubUsername +'/'+ path +'? callback=JSON_CALLBACK'}) } return {events: function () {return doRequest ('events');}, setUsername: function (newUsername) {githubUsername = newUsername;}};}])
Now that we have the setUsername method in our service, it is convenient for us to set the GitHub user name, and in any controller we apply, we can call the events () method without worrying about whether the username setting in the scope object is correct.
Services in our app
In our application, we need to create corresponding services for three elements: audio element, player element, and nprService. The simplest thing is audio service, remember, do not have any manipulation of DOM in controller, if doing so will contaminate your controller and leave potential dangers.
In our application, there is an instance of the audio element element in PlayerController
App.controller ('PlayerController', [' $scope','$http', function ($scope, $http) {var audio = document.createElement ('audio'); $scope.audio = audio; / /.
Instead of setting the audio element in controller, we can create a singleton audio service
App.factory ('audio', [' $document', function ($document) {var audio = $document [0] .createElement ('audio'); return audio;}])
Note: we use another built-in service, the $document service, which is a reference to the window.document element (the root object of javascript in all html pages).
Now, instead of creating this audio element in controller, we can reference this audio element in our PlayController
App.controller ('PlayerController', [' $scope','$http', 'audio', function ($scope, $http, audio) {$scope.audio = audio
Although we don't seem to enhance the functionality of the code or make it clearer, if one day PlayerController no longer needs audio service, we just need to simply delete the dependency. At that time, you will be able to experience the beauty of this kind of code writing!
Note: now we can share audio service in other applications, because it is not bound with features specific to this application.
To see the effect, let's build the next service: player service, and in our current loop, we have attached the play () and stop () methods to PlayController. These methods are only related to playing audio, so it's not necessary to bind to PlayController. In short, it's best to use PlayController to call player service API to manipulate the player without knowing the details.
Let's create player service. We need to inject the warm audio service we just created into player service.
App.factory ('player', [' audio', function (audio) {var player = {}; return player;}])
Now that we can move the play () method originally defined in PlayerController to player service, we also need to add the stop method and store the player state.
App.factory ('player', [' audio', function (audio) {
Var player = {
Playing: false
Current: null
Ready: false
Play: function (program) {
/ / If we are playing, stop the current playback
If (player.playing) player.stop ()
Var url = program.audio [0] .format.mp4. $text; / / from the npr API
Player.current = program; / / Store the current program
Audio.src = url
Audio.play (); / / Start playback of the url
Player.playing = true
}
Stop: function () {
If (player.playing) {
Audio.pause (); / / stop playback
/ / Clear the state of the player
Playerplayer.ready = player.playing = false
Player.current = null
}
}
}
Return player
}])
Now that we have a full-featured play () and stop () method, we don't need to use PlayerController to manage playback-related operations, we just need to give control to the player service in PlayController.
App.controller ('PlayerController', [' $scope', 'player', function ($scope, player) {$scope.player = player;}])
(note: sample screenshot, please go to the original text to test)
Note: when using player service, we don't need to think about audio service, because player will help us with audio service.
Note: when the audio playback ends, we do not reset the status of the player. The player will think that he has been playing.
To solve this problem, we need to use the $rootScope service (another built-in service for Angular) to capture the ended event of the audio element. We inject the $rootScope service and create an event listener for the audio element
App.factory ('player', [' audio','$rootScope', function (audio, $rootScope) {var player = {playing: false, ready: true, / /...}; audio.addEventListener ('ended', function () {$rootScope.$apply (player.stop ()); return player;}]))
In this case, $rootScope service is used to capture events, and notice that we call $rootScope.$apply (). Because the ended event triggers the peripheral Angular event loop. We will discuss event loop in a later article.
Finally, we can get the details of the current program, for example, we create a method to get the playback interval between the current event and the current audio (we will use this parameter to display the current playback progress).
App.factory ('player', [' audio','$rootScope', function (audio, $rootScope) {var player = {playing: false, / /. CurrentTime: function () {return audio.currentTime;}, currentDuration: function () {return parseInt (audio.duration);}; return player;}])
There is a timeupdate event in the audio element. We can update the playback progress based on this event.
Audio.addEventListener ('timeupdate', function (evt) {$rootScope.$apply (function () {playerplayer.progress = player.currentTime (); playerplayer.progress_percent = player.progress / player.currentDuration ();});})
Finally, we add a canplay event to indicate whether the audio in the view is ready
App.factory ('player', [' audio','$rootScope', function (audio, $rootScope) {var player = {playing: false, ready: false, / /...} audio.addEventListener ('canplay', function (evt) {$rootScope.$apply (function () {player.ready = true;});}); return player;}]))
Now that we have player service, we need to manipulate nprLink directive to get the player 'play', instead of $scope (note that this is optional, or we can create play () and stop () methods in PlayerController)
In directive, we need to reference the player of the local scope as follows:
App.directive ('nprLink', function () {return {restrict:' EA', require: ['^ ngModel'], replace: true, scope: {ngModel:'=', player:'='}, templateUrl:'/ code/views/nprListItem', link: function (scope, ele, attr) {scopescope.duration = scope.ngModel.audio [0] .room.$ text;})
Now, in order to integrate with our existing templates, we need to update the npr-link call mode of index.html
In the view interface, we call play.play (ngModel) instead of play (ngModel).
{{ngModel.title.$text}} Link
Logically, we need to add the player view to the overall view because we can encapsulate player data and state. View playerView directive and template.
Let's create the last service,nprService. This service is very similar to githubService. We use $http service to get the latest NPR programs.
App.factory ('nprService', [' $http', function ($http) {var doRequest = function (apiKey) {return $http ({method: 'JSONP', url: nprUrl +' & apiKey=' + apiKey +'& callback=JSON_CALLBACK'});} return {programs: function (apiKey) {return doRequest (apiKey);}};}])
At PlayerController, we call nprService's programs () (call $http service)
App.controller ('PlayerController', [' $scope', 'nprService',' player', function ($scope, nprService, player) {$scope.player = player; nprService.programs (apiKey) .success (function (data, status) {$scope.programs = data.list.story;});}])
We recommend using promises to simplify API, but for demonstration purposes, we will briefly introduce promises in the next post.
When the PlayerController is initialized, our nprService will get the latest programs, so we successfully encapsulate the function of obtaining NPR programs in nprService service. In addition, we add RelatedController to display the relevant content of the current program in the sidebar. When we get the latest program in our player service, we will watc the player.current property and display the content related to this attribute.
App.controller ('RelatedController', [' $scope', 'player', function ($scope, player) {$scope.player = player; $scope.$watch (' player.current', function (program) {if (program) {$scope.related = [] Angular.forEach (program.relatedLink, function (link) {$scope.related.push ({link: link.link [0]. $text, caption: link.caption.$text});}]
In the HTML code, we just reference the related links like we did with our NPR programs, using the ng-repeat directive:
Related content {{s.caption}}
As long as the player.current content changes, the relevant content displayed will also change.
In the next and final chapter of our "AngularJS-Seven steps from Rookie to expert," we will discuss dependency injection, routing, and product-level tools to make us use AngularJS faster.
To save this code base locally, make sure that you have installed the git,clone code base, and then check out the part6 branch of it:
Git clone https://github.com/auser/ng-newsletter-beginner-series.git git checkout-b part6. / bin/server.sh 's answer to the question on how to use services to complete the development of audio player applications is here. I hope the above content can be of some help to you. If you still have a lot of doubts to solve, you can follow the industry information channel for more related knowledge.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.