handle JavaScript plugin through angular js - javascript

I am new to AngularJS. I am developing a music app through AngularJS.
For HTML5 player I am using this: https://github.com/DIYgod/APlayer.
How to wrap aplyer inside angular so i only call directive to initialise player.
ex- INIT PLAYER
<div id="player1" class="aplayer"></div>
JS
var ap = new APlayer({
element: document.getElementById('player1'), // Optional, player element
narrow: false, // Optional, narrow style
autoplay: true, // Optional, autoplay song(s), not supported by mobile browsers
showlrc: 0, // Optional, show lrc, can be 0, 1, 2, see: ###With lrc
mutex: true, // Optional, pause other players when this player playing
theme: '#e6d0b2', // Optional, theme color, default: #b7daff
mode: 'random', // Optional, play mode, can be `random` `single` `circulation`(loop) `order`(no loop), default: `circulation`
preload: 'metadata', // Optional, the way to load music, can be 'none' 'metadata' 'auto', default: 'auto'
listmaxheight: '513px', // Optional, max height of play list
music: { // Required, music info, see: ###With playlist
title: 'Preparation', // Required, music title
author: 'Hans Zimmer/Richard Harvey', // Required, music author
url: 'http://7xifn9.com1.z0.glb.clouddn.com/Preparation.mp3', // Required, music url
pic: 'http://7xifn9.com1.z0.glb.clouddn.com/Preparation.jpg', // Optional, music picture
lrc: '[00:00.00]lrc here\n[00:01.00]aplayer' // Optional, lrc, see: ###With lrc
}
});
I am trying to use it by directive and pass template as
<div id="player1" class="aplayer"></div>
but I don't know how to add Aplayer JS to Angular.

You can initialize APlayer in a directive this way.
Use either <div class="aplayer"></div> or <div aplayer></div>
Attributes are declared using kebab-case in html code but you have to use camelCase to access them in directive code.
Note: data prefix is not required here. It's only used to prevent native html attribute collision.
(function() {
'use strict';
angular.module('app', []);
angular
.module('app')
.directive('aplayer', aplayer);
function aplayer() {
return {
restrict: 'AC',
link: function(scope, element, attrs) {
// `element` is the angular element the directive is attached to
// APlayer need the native one
var nativeElement = element[0];
var ap1 = new APlayer({
element: nativeElement,
narrow: false,
autoplay: true,
showlrc: false,
mutex: true,
theme: '#e6d0b2',
preload: 'metadata',
mode: 'circulation',
music: {
title: attrs["playerTitle"],
author: attrs["playerAuthor"],
url: attrs["playerUrl"],
pic: attrs["playerPic"]
}
});
ap1.on('play', function() {
console.log('play');
});
ap1.on('play', function() {
console.log('play play');
});
ap1.on('pause', function() {
console.log('pause');
});
ap1.on('canplay', function() {
console.log('canplay');
});
ap1.on('playing', function() {
console.log('playing');
});
ap1.on('ended', function() {
console.log('ended');
});
ap1.on('error', function() {
console.log('error');
});
}
};
}
})();
<!doctype html>
<html lang="en" ng-app="app">
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/aplayer/1.6.0/APlayer.min.js"></script>
<script src="script.js"></script>
</head>
<body>
<div class="aplayer"
data-player-title="Preparation"
data-player-author="Hans Zimmer/Richard Harvey"
data-player-url="http://devtest.qiniudn.com/Preparation.mp3"
data-player-pic="http://devtest.qiniudn.com/Preparation.jpg"></div>
</body>
</html>

Related

How can I send Global varibale data from view to controller?

I have my Angular view file like below.
<!DOCTYPE html>
<video id="myVideo" class="video-js vjs-default-skin"></video>
<script>
var dataUri;
var videoData;
var player = videojs("myVideo", {
controls: true,
width: 320,
height: 240,
fluid: false,
plugins: {
record: {
audio: true,
video: true,
maxLength: 100,
debug: true
}
}
}, function(){
// print version information at startup
videojs.log('Using video.js', videojs.VERSION,
'with videojs-record', videojs.getPluginVersion('record'),
'and recordrtc', RecordRTC.version);
});
// error handling
player.on('deviceError', function() {
console.log('device error:', player.deviceErrorCode);
});
player.on('error', function(error) {
console.log('error:', error);
});
// user clicked the record button and started recording
player.on('startRecord', function() {
console.log('started recording!');
});
// user completed recording and stream is available
player.on('finishRecord', function() {
console.log('player : ', player.recordedData.video.name);
videoData = player.recordedData;
console.log('finished recording: ', player.recordedData);
}
);
function getVideoData()
{
return videoData;
}
</script>
<button id="record" onClick="getVideoData();" ng-model="onFileSelect()"></button>
When player.on('finishRecord', function() function is called it will have the recorded video data in player.recordedData variable. What My problem is, I want to send the player.recordedData to the angular controller on button click whose id is record.
If the vairiable is defined globally, you can directly use it in any of controllers. Try to put you data in object.xxx format.
example:
var model = {videoData: null};
player.on('finishRecord', function() {
...
model.videoData = player.recordedData;
}
in controller:
//directly use it, ensure it has data
model.videoData

handle APlayer through angular js - play music dynamically

I am new to angular js - trying to build an audio play using Aplayer
Task:-
1. Play music dynamically
2. On click of album get json data and add to aplayer
(function() {
'use strict';
angular.module('app', []);
angular
.module('app')
.directive('aplayer', aplayer);
function aplayer() {
return {
restrict: 'AC',
link: function(scope, element, attrs) {
// `element` is the angular element the directive is attached to
// APlayer need the native one
var nativeElement = element[0];
var ap1 = new APlayer({
element: nativeElement,
narrow: false,
autoplay: true,
showlrc: false,
mutex: true,
theme: '#e6d0b2',
preload: 'metadata',
mode: 'circulation',
music: {
title: attrs["playerTitle"],
author: attrs["playerAuthor"],
url: attrs["playerUrl"],
pic: attrs["playerPic"]
}
});
ap1.on('play', function() {
console.log('play');
});
ap1.on('play', function() {
console.log('play play');
});
ap1.on('pause', function() {
console.log('pause');
});
ap1.on('canplay', function() {
console.log('canplay');
});
ap1.on('playing', function() {
console.log('playing');
});
ap1.on('ended', function() {
console.log('ended');
});
ap1.on('error', function() {
console.log('error');
});
}
};
}
})();
<!doctype html>
<html lang="en" ng-app="app">
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/aplayer/1.6.0/APlayer.min.js"></script>
<script src="script.js"></script>
</head>
<body>
<div class="aplayer"
data-player-title="Preparation"
data-player-author="Hans Zimmer/Richard Harvey"
data-player-url="http://devtest.qiniudn.com/Preparation.mp3"
data-player-pic="http://devtest.qiniudn.com/Preparation.jpg"></div>
</body>
</html>
How to pass music files dynamically to Aplayer on click of an album.
According to Aplayer source code, it's not possible to replace music track or playlist dynamically. API only expose setMusic method which allow to choose track index in music playlist.
To display your albums, you need to load them first using a service which will call your tracks API.
Once loaded, you can inject them to your aplayer directive and choose the index of the track to play.
Here is a sample snippet with :
a musicService to handle your music library
a TrackController to load and display your music library
a modified aplayer directive to handle tracks and current track index
Note: I'm using free music from Free Music Archive for this demo.
(function() {
'use strict';
angular.module('app', []);
angular
.module('app')
.factory('musicService', ['$timeout', musicService])
.controller('TracksController', ['$scope', 'musicService', TracksController])
.directive('aplayer', aplayer);
function musicService($timeout) {
return {
loadTracks: function() {
// Simulate a 1500 ms $http api call
return $timeout(function() {
return [{
title: 'Procrastinating in the Sun',
author: 'The Spin Wires',
url: 'https://freemusicarchive.org/music/download/e7fee95c2d7f7b1ea8d4260850a6128842eb85a4',
pic: 'https://freemusicarchive.org/file/images/artists/The_Spin_Wires_-_20170510154106040.jpg?width=290&height=290'
},
{
title: 'осоле',
author: 'Kosta T',
url: 'https://freemusicarchive.org/music/download/0e4d722be7bd7ca334970b5407b3e5654b95f7a2',
pic: 'https://freemusicarchive.org/file/images/tracks/Track_-_2017050264944176?method=crop&width=290&height=290'
}
];
}, 1500);
}
}
}
function TracksController($scope, musicService) {
$scope.loadingTracks = true;
$scope.showPlayer = false;
musicService.loadTracks()
.then(function(tracks) {
// Once tracks are loaded, update scope
$scope.tracks = tracks;
$scope.loadingTracks = false;
});
$scope.play = function(trackIndex) {
$scope.trackIndex = trackIndex;
$scope.showPlayer = true;
}
}
function aplayer() {
return {
restrict: 'AC',
scope: {
tracks: '=',
trackIndex: '='
},
link: link
};
function link(scope, element, attrs) {
var player = new APlayer({
narrow: true,
mode: "order",
music: scope.tracks
});
// Watch for trackIndex changes
scope.$watch(
function(scope) {
// Return the "result" of the watch expression as it's more efficient
// #see http://www.bennadel.com/blog/2852-understanding-how-to-use-scope-watch-with-controller-as-in-angularjs.htm
return scope.trackIndex;
},
function(currentIndex, previousIndex) {
// As currentIndex is an integer, if(0) equals if(false)
// But we can use a regular expression to check it's an integer
if (/\d/.test(currentIndex)) {
player.setMusic(parseInt(currentIndex));
player.play();
}
});
}
}
})();
<!doctype html>
<html lang="en" ng-app="app">
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/aplayer/1.6.0/APlayer.min.js"></script>
<style>
ul li {
list-style-type: none;
}
ul li * {
vertical-align: middle
}
</style>
</head>
<body ng-controller="TracksController">
<div ng-if="loadingTracks">Loading tracks, please wait...</div>
<ul>
<li ng-repeat="track in tracks">
<img ng-src="{{track.pic}}" width="64" height="64">
<button ng-click="play($index)">Play</button> {{track.author}} / {{track.title}}
</li>
</ul>
<div ng-if="tracks && showPlayer">
<h2>Now playing</h2>
<div>{{tracks[trackIndex].author}} / {{tracks[trackIndex].title}}</div>
<div class="aplayer" data-tracks="tracks" data-track-index="trackIndex"></div>
</div>
</body>
</html>

Element not found

I'm having a problem with an element not being found. I have this Ui-State from ui-router called AuthDesc, And for the templateURL I have this:
<head>
<link rel="stylesheet" type="text/css" href="stylesheets/normalize.css" media="screen">
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'>
</head>
<body>
<textarea id="SimpleMDE">
# This one autosaves!
By default, it saves every 10 seconds, but this can be changed. When this textarea is included
in a form, it will automatically forget the saved value when the form is submitted.
</textarea>
</body>
And for the Controller I have this:
(function(angular) {
var app = angular.module('ForumApp');
app.controller('authDescCtrl', ["$scope", "$mdDialog", "$state", "$firebaseObject","refService","currentAuth",authDescCtrl])
function authDescCtrl($scope, $mdDialog, $state, $firebaseObject,refService,currentAuth){
$scope.topic = $firebaseObject(refService.ref().child("Topics"))
$scope.goToPerson = function(person, event) {
$mdDialog.show(
$mdDialog.alert()
.title('Navigating')
.textContent('Inspect ' + person)
.ariaLabel('Person inspect demo')
.ok('Neat!')
.targetEvent(event)
);
};
$scope.goToTopic = function(avatar, date, email, title, uid, username, value) {
$state.go("authHome.topic", {
"AVATAR": avatar,
"DATE": date,
"EMAIL": email,
"TITLE": title,
"UID": uid,
"USERNAME": username,
"VALUE": value
})
}
}
new SimpleMDE({
element: document.getElementById("SimpleMDE"),
spellChecker: true,
autosave: {
enabled: true,
unique_id: "SimpleMDE",
},
});
})(angular);
You can see in the last couple lines of controller that there is a new MDE Generator, however the console states that the element cannot be found:
SimpleMDE: Error. No element was found.
I am confused. There is a textarea named SimpleMDE, but I do not know how is it not finding it. Here is a link to the code in the wild: https://ide.c9.io/amanuel2/fourm2
I am afraid that the Javascript loads before the HTML, so it doesn't recognize the texarea with ID SimpleMDE.
Wrap your widget initialization in window.onload event handler
For angular controller use:
angular.element(document).ready(function () {
new SimpleMDE({
element: document.getElementById("SimpleMDE"),
spellChecker: true,
autosave: {
enabled: true,
unique_id: "SimpleMDE",
},
});
});
you can do it also with this code :
$timeout(function() {
new SimpleMDE({
element: document.querySelector("#SimpleMDE"),
spellChecker: true,
autosave: {
enabled: true,
unique_id: "SimpleMDE",
}
});
});

MathJax not Rendering With Angular

The issue I have is this:
On my website, I pull my blog content from an external source which, the first time it's called upon to display, has to use a HTTP request to get. Also, the blog posts are written in Markdown, and I have to parse this to HTML.
I have this controller that goes out and gets the posts from github, decodes them, and parses them into HTML:
app.controller('content', function ($scope, github, html) {
github.getAllContent().then(function (res) {
var files = [];
res.data.forEach(function (obj) {
github.getFile(obj.path).then(function (res) {
res.data.content = marked(window.atob(res.data.content));
res.data.name = res.data.name.slice(0, res.data.name.indexOf('.'));
files.push(res.data);
})
});
$scope.files = files;
});
$scope.renderHtml = html.renderHtml;
});
html is this service
app.service('html', function ($sce) {
this.renderHtml = function (string) {
return $sce.trustAsHtml(string);
}
});
that allows me to insert the HTML into each HTML element like this: <elem>ng-bind-html="renderHtml(info) </elem>".
Whenever I do this, however, LaTeX content isn't rendered. I have configured MathJax to recognize $ ... $ as delimiters, but no matter what happens, I can't seem to get anything to render. I have even called the MathJax.Hub.Typeset() function or set the typeset callback in the MathJax.Hub.Queue function and it doesn't work. Is this because of the markdown parser I use or how the data is encoded? Or is it just a matter of typesetting the MathJax at the right time?
In this project, I use Angular ui-router, if that has anything to do with it.
I have used this (mathjaxBind.directive.js) directive in my project for MathJax and its working for me:
Plunker
mathjaxBind.directive.js
'use strict';
MathJax.HTML.Cookie.Set("menu", {});
MathJax.Hub.Config({
skipStartupTypeset: true,
messageStyle: "none",
extensions: ["tex2jax.js", "mml2jax.js", "MathML/content-mathml.js", "MathML/mml3.js"],
jax: ["input/MathML", "input/TeX", "output/SVG", "output/HTML-CSS", "output/NativeMML", "output/CommonHTML"],
"HTML-CSS": {
availableFonts: [],
styles: {".MathJax_Preview": {visibility: "hidden"}},
showMathMenu: false
},
"SVG": {
availableFonts: [],
styles: {".MathJax_Preview": {visibility: "hidden"}},
showMathMenu: false
},
"NativeMML": {
availableFonts: [],
styles: {".MathJax_Preview": {visibility: "hidden"}},
showMathMenu: false
},
"CommonHTML": {
availableFonts: [],
styles: {".MathJax_Preview": {visibility: "hidden"}},
showMathMenu: false
}
});
MathJax.Hub.Register.StartupHook("HTML-CSS Jax Ready", function () {
var FONT = MathJax.OutputJax["HTML-CSS"].Font;
FONT.loadError = function (font) {
MathJax.Message.Set("Can't load web font TeX/" + font.directory, null, 2000);
document.getElementById("noWebFont").style.display = "";
};
FONT.firefoxFontError = function (font) {
MathJax.Message.Set("Firefox can't load web fonts from a remote host", null, 3000);
document.getElementById("ffWebFont").style.display = "";
};
});
(function (HUB) {
var MINVERSION = {
Firefox: 3.0,
Opera: 9.52,
MSIE: 6.0,
Chrome: 0.3,
Safari: 2.0,
Konqueror: 4.0,
Unknown: 10000.0 // always disable unknown browsers
};
if (!HUB.Browser.versionAtLeast(MINVERSION[HUB.Browser] || 0.0)) {
HUB.Config({
jax: [], // don't load any Jax
extensions: [], // don't load any extensions
"v1.0-compatible": false // skip warning message due to no jax
});
setTimeout('document.getElementById("badBrowser").style.display = ""', 0);
}
})(MathJax.Hub);
MathJax.Hub.Register.StartupHook("End", function () {
var HTMLCSS = MathJax.OutputJax["HTML-CSS"];
if (HTMLCSS && HTMLCSS.imgFonts) {
document.getElementById("imageFonts").style.display = ""
}
});
angular.module('fsaApp')
.directive('mathjaxBind', function () {
return {
restrict: "A",
controller: ["$scope", "$element", "$attrs", function ($scope, $element, $attrs) {
$scope.$watch($attrs.mathjaxBind, function (value) {
//$($element).parent().find('math').wrap("<script type='math/mml'></script>");
$element.html(value);
MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
});
}]
};
});
Controller:
app.controller('MainCtrl', function($scope) {
$scope.info='<script type=\"math/mml\"><math>\n<mstyle displaystyle=\"true\">\n<mtext> N </mtext>\n<msub>\n<mrow>\n<mtext> O </mtext>\n</mrow>\n<mrow>\n<mn> 2 </mn>\n</mrow>\n</msub>\n</mstyle>\n</math></script>';
$scope.info2='<script type=\"math/mml\"><math>\n<mstyle displaystyle=\"true\">\n<mtext> C </mtext>\n<msub>\n<mrow>\n<mtext> H </mtext>\n</mrow>\n<mrow>\n<mn> 4 </mn>\n</mrow>\n</msub>\n</mstyle>\n</math></script>';
});
Library:
<script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
in HTML:
<div mathjax-bind="info"></div>
<div mathjax-bind="info2"></div>

Semantic-ui popup Dynamic content

Semantic-ui ver. 2.0.8.
I currently use the following method to load dynamic content in a pop-up
JAVASCRIPT
var popupContent = null;
var popupLoading = '<i class="notched circle loading icon green"></i> wait...';
$('.vt').popup({
inline: true,
on: 'hover',
exclusive: true,
hoverable: true,
html: popupLoading,
variation: 'wide',
delay: {
show: 400,
hide: 400
},
onShow: function(el) { // load data (it could be called in an external function.)
var then = function(r) {
if (r.status) {
popupContent = r.data; // html string
} else {
// error
}
};
var data = {
id: el.dataset.id
};
ajax.data('http://example.site', data, then); // my custom $.ajax call
},
onVisible: function(el) { // replace popup content
this.html(popupUserVoteContent);
},
onHide: function(el) { // replace content with loading
this.html(popupLoading);
}
});
HTML
<h2 data-id="123" class="vt">10</h2>
<div class="ui popup" data-id="123"></div>
There 's a way to simplify the whole process?
For example with a element.popup ('refresh') after loading the new content?
I tried:
JAVASCRIPT
...
if (r.status) {
$('.ui.popup[data-id="123"]').html(r.data);
}
...
but it does not work.
I also tried using (replace) data-content into h2.vt but nothing.
The only improvement that comes to mind is to make the code a little cleaner (you only really need the onShow event, which fires before the popup shows) and avoid using a global variable (popupContent).
That said, the main idea is mostly the same - when the popup is supposed to show, you replace its content with some fake content (the loading animation), then trigger $.ajax and update the popup content as soon as the request completes.
var popupLoading = '<i class="notched circle loading icon green"></i> wait...';
$('.vt').popup({
inline: true,
on: 'hover',
exclusive: true,
hoverable: true,
html: popupLoading,
variation: 'wide',
delay: {
show: 400,
hide: 400
},
onShow: function (el) { // load data (it could be called in an external function.)
var popup = this;
popup.html(popupLoading);
$.ajax({
url: 'http://www.example.com/'
}).done(function(result) {
popup.html(result);
}).fail(function() {
popup.html('error');
});
}
});

Categories