AngularJS downloads full video file for HTML5 video element - angularjs

I am building an application using AngularJS whose homepage displays the user 5 videos. The user can then click on any one of them to start playback.
The browser is currently downloading ALL source video files for each html5 video element displayed in the page. This is happening on Chrome and FireFox, but not on IE 11.
Here is the code for the app
AngularJS app initialization
var app = angular.module("hdv", ['ngCookies', 'infinite-scroll']).config(function ($interpolateProvider, $sceDelegateProvider) {
$sceDelegateProvider.resourceUrlWhitelist([
'self',
'https://*.vo.msecnd.net/**',
'https://*.domain.com/**'
]);
$interpolateProvider.startSymbol('[[[').endSymbol(']]]');
});
I use the $sceDelegateProvider to whitelist different origins, as the video source files are served via CDN's (whose domain names are obviously different than the uri of my page).
The html5 video elements are built using a customer directive:
app.directive("aVideo", function($http){
return {
template: '<video controls width="100%" ng-attr-poster=[[[post.creative.media.poster]]] ng-attr-preload="metadata" ng-src="[[[post.creative.media.uri]]]" ng-attr-type="[[[post.creative.media.contentType]]]"></video>',
scope:{
post: "=",
},
link: function(scope, element, attrs) {
$(element).find("video").on("play", function () {
$http.post('/post/' + scope.post.creative.cuid + '/views?_csrf=' + csrfToken)
.success(function(data){
})
.error(function(error){
});
});
},
}
});
Note that the video elements all have the preload=metadata attribute set, so downloading of the source file should not start.
As you can see above, the source file is taken from the scope object "[[[post.creative.media.uri]]]". Through debugging, I have come to realize that it is the resourceUrlWhitelist method the one that triggers the download. If I remove the whitelisting, then the video files are not downloaded anymore (but are also not displayed in the browser due to $sce insecure error). Also, if I set this uri using the $sce "resourceUrl" method on every "post" object, then the browser will download the entire file.
It seems that, whenever $sce is used to whitelist a domain or the origin of a file, the browser just downloads the entire file, without respective the fact that it is a source of a video element and thus the preload attribute should be honored.
I'd like to get input from the community on how to resolve this issue, as every time users download my homepage, their browsers are downloading about 500mb of video data that they do not need.

You should definitely use preload instead of ng-attr-preload.
Check whether the meta block is at the end of your file. If this is your case check this post on how to fix it: Why do webkit browsers need to download the entire html5 video (mp4) before playing?

Related

How to clear browser cache when launching updated version of application?

I am deploying my UI application which is made up of AngularJS, Grunt and other UI things.
Whenever i update my UI and redeploy it using apache-tomcat, Browser is always getting my resources from cache. (As the path of new resources like css, html are same)
User needs to do CTRL+F5 (Hard reload) to clear cache and use new resources.
How can i force browser to clear cache when i redeploy application?
If somehow i can use angular + grunt to do this task than also it is
fine.
I don't want to update the versioning of my files each time i redeploy the product. As my files internally downloading many html files as well.
So somehow i want to clear the browser cache only.
Thanks!
You can't update cache without filenames versioning. But you don't have to do it manually. If you use Grunt, just check out some npm packages. Like this one for example: https://www.npmjs.com/package/grunt-cache-breaker
On rebuild it will create new hashes for your assets and inject them into your html files. So when your users will download your html files (they are downloaded, they are not cached), these html files will contain assets like css and js with new names, so the browser will force download instead of taking these files from memory.
You can add version to your html files
app.factory('preventTemplateCache', function () {
return {
'request': function (config) {
if (config.url.indexOf('partials') !== -1) {
config.url = config.url + '?t=' + 101;
}
return config;
}
}
})
and also give version to .js files as
<script src='app.js?v=101'></script>
101 is version number

Serve up web files from different directory - Error 400 Bad Request

I have an MVC app that uses AngularJS. I am in the process of organizing the folder structure to be feature based rather than type based.
An example folder structure is now
App (Folder within main project, at same level as Views)
Assets
CSS
JS
Pages
Home
home.js
home.tests.js
home.html
About (etc)
Now the problem is that when ui-router tries to load home.html the web server throws a 400 error. If I go to the file manually in the browser it works. What is the problem here? Why can I not serve files up from this directory. Note that I actually right click the 400 message in the console and choose open in new tab. So I know the file I am looking at is the URL being requested from AngularJS
Here is my ui-router setup
.state('home', {
url: '/home',
templateUrl: '/app/pages/home/home.html',
controller: 'mainPageController'
})
Note:
I serve up a .js file from the same directory which seems to work fine!
I had the exact same problem and it was caused by another developer trying to fix an IE caching bug.
I found the solution here by Ben Cull: https://stackoverflow.com/a/30014936/710268.
//initialize get if not there
if (!$httpProvider.defaults.headers.get) {
$httpProvider.defaults.headers.get = {};
}
//disable IE ajax request caching
$httpProvider.defaults.headers.get["If-Modified-Since"] = "Fri, 01 Jan 2010 00:00:00 GMT";
My problem was that the "If-Modified-Since" header was set to '0' and for some reason that was causing html template files to not load.
By default the router is going to start at the top level of your MVC project (i.e. where your Views and App folder sit) and not the folder where your JavaScript is served from.
So in Angular your templateUrl needs to be App/Pages/Home/home.html.
So in your angular router configuration have the property:
templateUrl: 'App/Pages/Home/home.html'

Is it possible to build a hybrid app with Angular?

I build an AngularJS application that I expected to work as a hybrid application for mobile devices. As such the application would run locally from the file system.
When the $routeProvider gets the html file I get the following message.
This is a CORS violation obviously but the file is local and trying to access another local file. It's not like a web site is trying to access a clients local files. This is the client.
I can't spin up a web server to serve up the local files because this will be packaged up and deployed as a local application.
I know people build hybrid mobile applications all the time. What I can't figure out is how they do this with AngularJS and why AngularJS doesn't either offer a solution or prescribe how to get around CORS.
I'm open to all suggestions. Thanks all.
XMLHttpRequest cannot load file:///D:/SubversionRits/SourceCode/Verso%20-%20Mashup%20Proposal/MarshupSource/MashupCoreUI/core/apps/mashup/welcome/welcome.html. Cross origin requests are only supported for protocol schemes: http, data, chrome-extension, https, chrome-extension-resource. VM36 angular.js:8380
Error: Failed to execute 'send' on 'XMLHttpRequest': Failed to load 'file:///D:/SubversionRits/SourceCode/Verso%20-%20Mashup%20Proposal/MarshupSource/MashupCoreUI/core/apps/mashup/welcome/welcome.html'.
Here is my route config
mashupApp.config(function ($routeProvider, $httpProvider) {
// I've tried all these with no effect.
//$httpProvider.defaults.headers.common['Access-Control-Allow-Origin'] = '*';
//$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
//$routeProvider.defaults.headers.common['Access-Control-Allow-Origin'] = '*';
//$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
//$httpProvider.defaults.useXDomain = true;
//delete $httpProvider.defaults.headers.common['X-Requested-With'];
$routeProvider
.when('/about', {
templateUrl: 'apps/mashup/about/about.html',
controller: 'aboutController',
resolve: {
loadMyCtrl: ['$ocLazyLoad', function ($ocLazyLoad) {
// you can lazy load files for an existing module
return $ocLazyLoad.load({
name: 'mashupApp',
files: ['apps/mashup/about/aboutController.js', 'apps/mashup/~appServices/dataService.js']
});
}]
, sessionLoad: function ($route, sessionLoad) { return sessionLoad.loadCompleted(); }
}
})
.when('/', {
templateUrl: 'apps/mashup/welcome/welcome.html',
sessionLoad: function ($route, sessionLoad) { return sessionLoad.loadCompleted(); }
}
})
;
});
I don't know the details, but I'm pretty sure HabitRPG's Android app uses Angular.
https://github.com/HabitRPG/habitrpg-mobile
Ok, I figured it out.
Running a web app from a file doesn't work because of CORS but when you are packaged up in Phonegap or Cordova inside the Intel XDK everything works.
I took my application and created a blank Intel XDK project and copied my web files to it without changing anything.
It all worked!
Thanks for those who offered ideas and suggestions. I really appreciate it.
I see how this can work now.
If you want to create a hybrid mobile app with AngularJS, you should definitely checkout the Ionic Framework.
From the Ionic website:
A match made in heaven. Ionic utilizes AngularJS in order to create a framework most suited to develop rich and robust applications. Ionic not only looks nice, but its core architecture is for serious app development, and AngularJS ties in perfectly.
You can't access the files directly due to browser security settings, but you can store data etc in localstorage and use that when the app is offline.
Someone has put together an example here http://amitavroy.com/justread/content/articles/html5-local-storage-angular-js

AngularJS and PhoneGap: $location.path causes subsequent tempateUrl lookup to fail

I'm having trouble getting path lookup to work with a AngularJS v1.2.0 and PhoneGap/Cordova Android application. I've come pretty far with html5mode(true) by setting <base href="."/> in index.html and then changing $routeProvider.when('/') to $routeProvider.when('/android_asset/www/index.html'). After that I am able to get redirectTo('login') to reach $routeProvider.when('/login') and there render templateUrl: 'static/partials/login.html' as expected.
The problem I have is that if I instead try to redirect to the login page from my Javascript code with $location.path('/login');, the route is found but templateUrl loading fails with an insecurl exception.
I've tried whitelisting access to file:// by using the new angular-sanitize module, but that does not help.
How can I make $location.path() do the same things as redirectTo so that the partial is loaded? Or is there some other way to solve this problem?
UPDATE: I got a bit forward by adding a call to replace() after the path function, e.g.:
$location.path('/login').replace();
but that seems like a hack, and it still causes the templateUrl in the otherwise route to fail with the same exception.
Any ideas on what might be wrong? Is it that html5mode(true) just does not work at this moment with Phonegap and the only way to fix this is to set it to false and add hashtags to every path (like is done in the angular phonegap seed project)?
For future reference, this is how I managed to solve the problem:
AngularJS currently does not seem to support html5mode(true) inside a Cordova application because of the insecurl problem I reported. What I had to do is add
var h5m = (typeof html5Mode !== 'undefined') ? html5Mode : true;
$locationProvider.html5Mode(h5m);
which gives me the possibility to explicitly set html5Mode in the PhoneGap index.html with a global variable:
<script>
var html5Mode = false;
</script>
So now $location.path('/login') as well as redirectTo: 'login' works, but links in html files, don't. To get those working in PhoneGap, with html5Mode disabled, I had to add #/ in front of every link, e.g. login.
That makes PhoneGap work, but breaks the web page which uses History API with html5Mode(true). The last piece of the puzzle was to add <base href="/"/> to the web page's index.html (and leave it out of the index.html of the PhoneGap project.) So now even though I have a link that says #/login in the web page, I get to the url http://example.com/login and don't see any hashes in the address bar.
**
So in the end I have History API working in my web page and History API disabled in the PhoneGap project (where there really is no need for History API as there is no address bar). The only downside is the extra #/ I have to put in each template html file, but that is a minor annoyance compared to the ability to use all of the same html and javascript files for both web and mobile.
I had this same problem as well. I managed to fix it by skipping the leading slash in the route config:
$routeProvider
// route for the foo page
.when('/foo', {
templateUrl: 'foo.html', //previously: '/foo.html'
controller: 'fooController'
}) //etc.

AngularJS 1.2 Not allowed to load local resource

I know it would be great if the file wouldn't link to local resource, but using phonegap/steroids framework, FILE_URI returns "file:///Users/" path which I can use for uploading to S3 or else, but Angular won't show it in the template.
Is there a possible solution? I tried adding config to my app
.config(function ($compileProvider){
$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|tel):/);
$compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|tel):/);
})
but it seems that doesn't have impact on the error.
I can base64 encode my images (then works), but I would like to avoid this if possible.
thanks
See the Camera example in the Steroids Kitchensink app, where the Cordova File API is used to move the picture from the tmp folder to the Steroids app's User Files folder. Since Steroids's localhost looks for assets both in the App folder and User Files folder, you can use an absolute path, e.g. src="/my_image.png". See also the App Structure on Device guide for more information on the App and User Files folder.

Resources