I have an Angular app that pulls in many audio files from a database. I'm using audio.js by Anthony Kolber as the HTML5 player, where the associated wrapper and html are generated from the javascript. The problem is the markup is doubling and I can't figure out why. It does so both within or without an ng-repeat and causes a continuous 'undefined' error when setting width to the loading and progress bars.
The javascript is quite long and difficult to paste here. I've created a simplified version of the problem with the code here as well as a live demo here.
The original HTML:
<!-- audio links -->
<div ng-repeat="audio in medias | orderBy: 'track'" my-repeat-directive>
<span><em>{{audio.title}}</em></span>
<audio src="" dynamic-url dynamic-url-src="{{audio.url}}" preload="auto" />
</div>
The rendered HTM:
<div ng-repeat="audio in medias | orderBy: 'track'" my-repeat-directive="" class="ng-scope">
<span><em class="ng-binding">Glass Jungle 1</em></span>
<div class="audiojs loading" classname="audiojs" id="audiojs_wrapper0">
<div class="audiojs " classname="audiojs" id="audiojs_wrapper3">
<audio src="audio_files/Glass_Jungle_sample1.mp3" dynamic-url="" dynamic-url-src="Glass_Jungle_sample1.mp3" preload="auto"></audio>
<div class="play-pause">
<p class="play"></p>
<p class="pause"></p>
<p class="loading"></p>
<p class="error"></p>
</div>
<div class="scrubber">
<div class="progress" style="width: 0%;"></div>
<div class="loaded" style="width: 100%;"></div>
</div>
<div class="time">
<em class="played">00:00</em>/<strong class="duration">01:25</strong>
</div>
<div class="error-message"></div>
</div>
<div class="play-pause">
<p class="play"></p>
<p class="pause"></p>
<p class="loading"></p>
<p class="error"></p>
</div>
<div class="scrubber">
<div class="progress"></div>
<div class="loaded"></div>
</div>
<div class="time">
<em class="played">00:00</em>/<strong class="duration">00:00</strong>
</div>
<div class="error-message"></div>
</div>
I downloaded your code and simplified it a bit and it worked for me:
<!-- audio links -->
<div ng-repeat="audio in medias | orderBy: 'track'">
<span><em>{{audio.title}}</em></span>
<audio src="" dynamic-url dynamic-url-src="{{audio.url}}" preload="auto" />
</div>
<!-- JavaScript -->
<!-- jQuery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!-- angularJS -->
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<!-- AngularJS Scripts -->
<script>
var app = angular.module('myApp', []);
app.controller('mainCtrl', function($scope, $rootScope) {
$scope.medias = [{
"track": 1,
"title": "Glass Jungle 1",
"url": "Glass_Jungle_sample1.mp3"
}, {
"track": 2,
"title": "Glass Jungle 2",
"url": "Glass_Jungle_sample2.mp3"
}, {
"track": 3,
"title": "Glass Jungle 3",
"url": "Glass_Jungle_sample3.mp3"
}];
audiojs.events.ready(function() {
var as = audiojs.createAll();
});
});
app.directive('dynamicUrl', function() {
return {
restrict: 'A',
link: function postLink(scope, element, attr) {
element.attr('src', 'audio_files/' + attr.dynamicUrlSrc);
}
};
});
</script>
The rest is the same. I didn't delve too deeply into the whys of why your code was having problems, and it's been a while since I worked with angular, but I think it had to do with myRepeatDirective, which is executed 3 times, once for each audio file. I'm guessing the markup was only duplicated twice because the second time through it encountered the javascript errors to prevent it from executing a third time.
Related
i have two ng-repeats that i would like to connect together using their unique id. The idea is that you click a movie poster and the corresponding streaming video will come up the screen above using CSS hide/show. This is what i have so far:
<div class="contentContainer" ng-app="webtest">
<div class="" ng-controller="LandingPageController">
<div class="videoContainer" ng-repeat="movie in movies" >
<video width="800" controls>
<source src="{{movie.stream}}" type="video/mp4">
</video>
</div>
<div class="moviesContainer">
<div class="movieCell" ng-repeat="movie in movies">
<a href="#tab{{movie.id}}">
<img class="movieCellImage" src="content/images/moviePosters/{{movie.images.cover}}">
<div class="movieCellImageBackground">
<div class="movieCellTitle">{{movie.title}} {{movie.id}}</div>
</div>
</a>
</div>
</div>
</div>
</div>
If you use Angular, you don't have to/ should use jQuery.
Angular allows you to handle click event with ng-click.
To your <a> add ng-click="select_video(movie.id)" (you can also remove href).
And you controller should look like this:
var app = angular.module('{your-app-id}', []);
app.controller('LandingPageController', function ($scope) {
$scope.selected_id = null;
$scope.movies = (...) /* The array of movies. */
$scope.select_video = function(id) {
$scope.selected_id = id;
};
});
Then, to every .videoContainer > * add ng-if="selected_id == movie.id".
Should work, let me know if it doesn't.
EDIT:
Also reorganize your HTML like this:
<div ng-controller="...">
<div class="videoContainer" ng-repeat="...">
<div ng-if="...">
<!-- <video /> here, and stuff visible only if this video is selected -->
</div>
<!-- Your <a /> -->
</div>
</div>
You don't need 2 loops. Create a reference to selected item, and set it up in the loop like:
<a ng-click="selectedMovie = movie">...</a>
Let then angular do everything for you.
<div ng-controller="LandingPageController">
<video width="800" controls>
<source src="{{selectedMovie.streams[0].url}}" type="video/mp4">
</video>
<div class="newscontainer">{{selectedMovie.id}} CLICKED</div>
<div class="moviesContainer" id="tabs">
<div class="movieCell" ng-repeat="movie in movies">
<a ng-click="selectedMovie = movie">
<img class="movieCellImage" src="content/images/moviePosters/{{movie.images.cover}}">
<div class="movieCellImageBackground">
<div class="movieCellTitle">{{movie.title}} {{movie.id}}</div>
</div>
</a>
</div>
</div>
</div>
EDIT:
Not tested, may not work. If so, try <a ng-click="$parent.selectedMovie = movie">...</a>
So to put things in perceptive I got this code that searches streams (Json) and filter is game,and it filters it by games and it all works fine.
var app = angular.module('myStream', []);
app.controller('customersCtrl', function($scope, $http) {
$http.get("https://api.twitch.tv/kraken/streams").then(function(response) {
$scope.myName = response.data.streams;
$scope.link = "http://player.twitch.tv/?channel=";
});
});
<div class="container-fluid" ng-controller="customersCtrl3">
<div class="row">
<div class="col-md-2">
<!--Sidebar content-->
<div id="searchBoxes">
Search by game: <input type="text" ng-model="search.game">
Search by language: <input type="text" ng-model="search.channel.language">
</div>
</div>
<div ng-app="myApp" ng-controller="customersCtrl" class="video">
<iframe ng-repeat="x in myName | filter:search "
src="{{link+x.channel.name| trustThisUrl}}"
height="250"
width="320"
frameborder="1"
autoplay="false"
preload="no"
scrolling="no"
allowfullscreen="true">
</iframe>
</div>
</div>
</div>
Now I want to know how to do same thing(this where is ng-model="search.game") and pass it in filter.
I tried something like this with select but it doesn't work,just can't find way to pass it same like this above.I know that above is solved problem and it works,but I need to make it this way or similiar,games categorization and when one is selected it passes it in filter and shows streams with only that game.Thank you.
<div ng-controller="customersCtrl4">
<p>selected item is : {{selectedItem}}</p>
<select ng-model="selectedItem.game">
<option ng-repeat="x in myGames" value="{{x.game.name}}">{{x.game.name}}</option>
</select>
</div>
<div ng-controller="customersCtrl" sytle="color:white">
<ul ng-repeat="x in myName | filter:selectedItem">
<li> <a ng-href="{{x.channel.url}}" target="_blank">{{x.channel.name}}</a>
</li>
</ul>
</div>
I have a template whereby I load details into via a JSON file. The content that is loaded in accompanies a video embed. Everything from the JSON files are working great, but the same video appears on every item. Is there a way that I can load individual videos assigned to each JSON file?
Here is the template:
<div class="container" ng-repeat="guide in guides">
<div class="row">
<div class="col-md-12">
<br/>
<p><a ng-href="#/"><span class="glyphicon glyphicon-home"></span> Back to Guide List</a></p>
<h1><span class="glyphicon glyphicon-play-circle"></span> Watch {{ guide.title }}</h1>
<span>{{ guide.info }}</span><br/><br/>
</div>
<div class="col-md-12">
<video video="marvel">
</video><!--This is the bit I'm having an issue with -->
</div>
<div class="col-md-6">
<h3><span class="glyphicon glyphicon-education"></span> Background to {{ guide.title }}</h3>
<span>{{ guide.background }}</span><br/><br/>
</div>
<div class="col-md-6">
<h3><span class="glyphicon glyphicon-save"></span> Downloads for {{ guide.title }}</h3><br/>
<a ng-href="{{ guide.pdf }}" target="_blank"><span class="glyphicon glyphicon-floppy-save"></span> Download Help Guide PDF</a><br/><br/>
<a ng-href="{{ guide.video }}" target="_blank"><span class="glyphicon glyphicon-floppy-save"></span> Download Video</a>
</div>
</div>
</div>
I'm unable to bind any data into the video tag (which is a directive I've built) - so does anyone have any suggestions?
Thanks in advance.
It should help if you reference a different video in each repeat iteration ;-)
<div class="col-md-12">
<video src="{{guide.my_video_uri}}">
</video>
</div>
If src=".." doesn't work, try ng-src="..".
thanks for the suggestion. I have in fact, tried this - the video tag is a little misleading; as it a custom directive called "video".
<video video="{{ guide.video }}">
</video>
this just brings up the error: Cannot GET /%7B%7B%20videoUrl%20%7D%7D
The directive brings in youtube embeds - which I am using for testing purposes first. The intention was to adjust the trustAsResourceUrl to another form of embed afterwards. The directive code is here below (i have changed the tag from video to video-player)
guideApp.directive('videoPlayer', function ($sce) {
'use strict';
return {
restrict: 'E',
scope: { video: '=' },
replace: true,
template: '<div class="embed-responsive embed-responsive-16by9"><iframe class="embed-responsive-item" width="100%" height="100%" src="{{ videoUrl }}" frameborder="0" allowfullscreen></iframe></div>',
link: function (scope) {
scope.$watch('videoPlayer', function (videoLink) {
if (videoLink) {
scope.videoUrl = $sce.trustAsResourceUrl("https://www.youtube.com/embed/" + videoLink);
}
});
}
};
});
I have an app which is pulling in data from another site using the Wordpress plugin WP-API.
I'm suing AngularJS to then display this information, I'm really new to AngularJS so my problem is that the correct information is being pulled in from the posts but HTML tags are showing such as <p>text</p>.
I'm pulling in data like this (a snippet of my code)-
<script>
var app = angular.module('myApp', []);
app.controller('aLlCtrl', function($scope, $http) {
var url = 'http://scd.blaze.wpengine.com/wp-json/posts?type=listings&filter[listing_area]=channel';
$http.get(url).then(function(data) {
$scope.data = data.data;
});
});
</script>
<body ng-app="myApp">
<!--SHOOTING TYPE-->
<div id="All" class="descshoot">
<div ng-controller="aLlCtrl">
<div ng-repeat="d in data">
<h2 class="entry-title title-post">{{d.title}}</h2>
<div id="listing-image"><img src="{{d.acf.logo}}"></div>
<div id="listing-contact">Contact: {{d.acf.contact}}, {{d.acf.position}}</div>
<div id="listing-address-1">
{{d.acf.address_1}}, {{d.acf.address_2}} {{d.acf.address_3}} {{d.acf.town}} {{d.acf.county}} {{d.acf.postcode}}
</div>
<div id="listing-phone">Telephone: {{d.acf.telephone}}</div>
<div id="listing-mobile">Mobile: {{d.acf.mobile}}</div>
<div id="listing-email">Email: {{d.acf.email}}</div>
<div id="listing-website">Website: {{d.acf.website}}</div>
<div id="listing-established">Established: {{d.acf.established}}</div>
<div id="listing-about">About: {{d.acf.about}}</div>
<div id="listing-mailingaddress">Mailing Address: {{d.acf.mailing_address_}}, {{d.acf.mailing_address_2}}, {{d.acf.mailing_address_3}}, {{d.acf.mailing_town}}, {{d.acf.mailing_county}}, {{d.acf.mailing_postcode}}</div>
<div id="listing-directions">Directions: {{d.acf.directions}}</div>
<div id="scd-link">View on The Shooting Club Directory</div>
</div>
</div>
</div>
</body>
And here is a (non-working) pen of my code - http://codepen.io/anon/pen/yePYdq and the site where it's working http://dev.5874.co.uk/goshooting/regions/channel-islands/
Any help would be much appreciated,
Thanks!
You need to use ng-bind-html attribute: JSFiddle
DOCUMENTATION
HTML:
<div ng-app="myApp" ng-controller="myCtrl">
{{test}} <!--will show '<p>test</p>'-->
<div ng-bind="test"></div> <!--will show '<p>test</p>'-->
<div ng-bind-html="test"></div> <!--will show 'test'-->
</div>
JS:
angular.module("myApp", ["ngSanitize"])
.controller("myCtrl", function($scope) {
$scope.test = "<p>test</p>";
});
Note: Don't forget to include ngSanitize to your module.
For a metro style app, in Windows 8, I have a list of article that i pass to a flip View Control. Each Article have a description text in HTML which contains javascript. I know we have to use this function to load unsafe content to innerHTML :
var someElement = document.getElementById('someElementID');
MSApp.execUnsafeLocalFunction(
function() { someElement.innerHTML = '<div onclick="console.log(\"hi\");">hi</div>' }
);
But how can i achieve that when my innerHTML property is within a template?
here is my template :
<div id="ItemTemplate" data-win-control="WinJS.Binding.Template">
<div class="itemDetail fragment">
<header aria-label="Header content" role="banner">
<!-- <button class="win-backbutton" aria-label="Back" disabled></button>-->
<h1 class="titlearea win-type-ellipsis">
<span class="pagetitle"></span>
</h1>
</header>
<section aria-label="Main content" role="main">
<article>
<img class="article-image" src="#" style="width: 300px; height: 200px;" data-win-bind="src: urlImage; alt: title" />
<div class="item-content" data-win-bind="innerHTML: description"></div>
</article>
</section>
</div>
</div>
for this flipVIew :
<div id="basicFlipView"
data-win-control="WinJS.UI.FlipView"
data-win-options="{itemTemplate:select('#ItemTemplate')}">
</div>
and here is how i Fill it :
var dataControl = document.getElementById("basicFlipView").winControl;
dataControl.itemDataSource = dataList.dataSource;
dataControl.currentPage = myState.index;
Thank you very much for your help
EDIT : As Dominic Hopton suggested I used a WinJS.Binding.initializer. This is a quite complex way of doing a binding. I've done this but it doesn't work properly. Do you see something wrong :
var toUnsafeHTML = WinJS.Binding.initializer(
function toUnsafeHTML(source, sourceProperty, dest, destProperty) {
function setUnsafeHTML() {
MSApp.execUnsafeLocalFunction(
function () { dest.innerHTML = source.innerHTML }
);
}
return WinJS.Binding.bind(source, {
innerHTML : setUnsafeHTML}
);
}
);
//
// Binding initializers have to be public, so publish this out
// via a namespace
//
WinJS.Namespace.define("TemplateControl", {
toUnsafeHTML: toUnsafeHTML
});
and in the html :
<div id="ItemTemplate" data-win-control="WinJS.Binding.Template">
<div class="itemDetail fragment">
<header aria-label="Header content" role="banner">
<!-- <button class="win-backbutton" aria-label="Back" disabled></button>-->
<h1 class="titlearea win-type-ellipsis">
<span class="pagetitle"></span>
</h1>
</header>
<section aria-label="Main content" role="main">
<article>
<img class="article-image" src="#" style="width: 300px; height: 200px;" data-win-bind="src: urlImage; alt: title" />
<div class="item-content" data-win-bind="innerHTML: TemplateControl.toUnsafeHTML"></div>
</article>
</section>
</div>
</div>
It never enter the setUnsafeHTML function...
I'm not sure this is even possible using databinding, at least not using any of several techniques I tested.
That being said...even if you COULD do this...if the articles you are loading are coming from the Internet, this would be a VERY bad idea.
If you load script from the network, you expose yourself to the possibility that it contains malicious code. There's a reason this limitation exists, which is to protect you (and more importantly, those who use your app) from potential exploits.
If you haven't already, please read the docs for execUnsafeLocalFunction, as they detail why attempting to inject script from the web in the local app context is a bad idea:
http://msdn.microsoft.com/en-us/library/windows/apps/Hh767331.aspx
See also (the section titled "Dynamically adding HTML"):
http://msdn.microsoft.com/en-us/library/windows/apps/hh465380.aspx
and:
http://msdn.microsoft.com/en-us/library/windows/apps/hh465388.aspx
which lists the tags, attributes, and CSS properties that are considered safe or unsafe.
Hope that helps!