I'm integrating a media player in my app using the "Video For Everybody" generator. As the player features a fallback to flash if the browser doesn't support HTML5 video
and audio
I have to build an object
element with param
attributes with the video and placeholder (image) source.
As expected I run into the classical problem of expressions not being resolved in time, my browser sends requests to my.media.com/{{video.src}}
rather then my.media.com/somevideo.mp4
Unfortunately there are several attributes (poster, flashvars, placeholder
to name a few) where I face the same problem. How would I go about creating the same behavior as the ng-src or ng-href directives? I tried looking for the relevant source code, but I haven't found it. Here is a snippet which showcases the problematic HTML,
<video controls="controls" poster="{{mediaModel.mediaFile2}}" width="300" height="150">
<source ng-src="{{mediaModel.mediaFile}}" type="{{mediaModel.contentType}}" />
<object type="application/x-shockwave-flash" data="http://player.longtailvideo.com/player.swf" width="300" height="150">
<param name="movie" value="http://player.longtailvideo.com/player.swf" />
<param name="allowFullScreen" value="true" />
<param name="wmode" value="transparent" />
<param name="flashVars" value="{{'controllerbar=over&image=' + media.mediaFile2 + '&file=' + mediaModel.mediaFile}}" />
<img ng-src="{{mediaModel.mediaFile2}}" width="300" height="150" title="{{mediaModel.uploadedTime}}" />
</object>
You can now use ng-attr-poster
, or more generally: ng-attr-whatever
.
Finding the source of build-in directive is made easy on the official API documentation. In this case go to the documentation of ngSrc , at the top of the page you will see two buttons, "Improve this doc" and "View source", click on "View source" and it will automatically take you to the correct source file where the directive is defined. This works across all build-in directive, very handy!
Below I'm pasting the code for ngSrc, which interestingly enough does not look complicated at all, the crucial line seems to be priority: 99
, based on the comment next to it means that directives with priority of 99 will run after attributes have been interpolated.
// ng-src, ng-srcset, ng-href are interpolated
forEach(['src', 'srcset', 'href'], function(attrName) {
var normalized = directiveNormalize('ng-' + attrName);
ngAttributeAliasDirectives[normalized] = function() {
return {
priority: 99, // it needs to run after the attributes are interpolated
link: function(scope, element, attr) {
attr.$observe(normalized, function(value) {
if (!value)
return;
attr.$set(attrName, value);
// on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
// then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
// to set the property as well to achieve the desired effect.
// we use attr[attrName] value since $set can sanitize the url.
if (msie) element.prop(attrName, attr[attrName]);
});
}
};
};
});
Given the above it should be trivial to implement your own directive.
So the most generic, maintainable, configurable and reusable solution is to create a custom directive that will handle it for you.
Look at this -->PLNKR<-- there is practically all you need there. You have just to weak it a little bit.
How it works: to the directive you pass the configuration object (if you need more objects just create additional attributes). The element can be in two states: ready or not. And $scope.isReady
just states if all the ingredients have been collected. If so ngSwitch
loads the videoPlayer template and since all the information is there no unwanted requests are sent.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With