Dynamically loaded AngularJS application - javascript

I'm looking to integrate an AngularJS web application into a number of websites. I'd like to be able to provide each website administrator with an HTML code, such as the following:
<div id='angular-integration-app'></div><script src="widget.js"></script>
With this HTML code inserted into the website, the website should load AngularJS and insert an AngularJS application as a child element of the element labeled with the ID of "angular-integration-app."
This Plunker has an implementation, however this implementation isn't working. It fails intermittently, with an error of:
Uncaught ReferenceError: angular is not defined application.js:1
Uncaught Error: [$injector:modulerr] angular.js:38
I've noticed that it usually works fine the first time it's loaded, but when the browser refresh button is pressed, it often fails. This is particularly true when it's not being hosted through Plunker.
Please advise on the best way to create a dynamic AngularJS application integration that works all the time.

This inconsistent behavior is because sometimes the page is cached and the code is executed synchonously, sometimes it does not.
To fix that, you need to wait for angular to be ready, then declare your module, and then bootstrap the document with your module. You cannot use ng-app in the HTML if the bootstrapping is executed "afterwards" (asynchronously, out of angular context). I have made the changes to show you how it should be:
var element = document.querySelector('#angular-integration-app');
angular.element(element).ready(function() {
var app = angular.module('myapp', []);
app.directive('customForm', function() {
return {
restrict: 'A',
template: 'hello world'
};
});
angular.bootstrap(element, ['myapp']);
});
http://plnkr.co/edit/7KbD1Okwx0MwhDIJXIGE?p=preview
Alternatively, if you don't want angular to mess up with your target html (and what happens if he is using another version of angularjs himself?), you could create an iFrame to isolate your angular, style, and code.

The code in this Plunker looks like it solves the problem. I'm now adding AngularJS as a child of the head element (the variable named "script"), and holding off on modifying the DIV or loading the AngularJS application until "script.onload." I incorporated some of the ideas from floribon's post into this Plunker as well.
script.onload = function() {
// code here
};

Related

How to dynamically set and Angular JS page's meta og tags for Facebook sharing?

This question is closely related to this one I asked a couple of days ago.
I am building an angularJS web-application. I am currently trying to use the ngMeta module to allow the web-app to produce dynamic entries for page title and for meta tags so that' Facebook will know to display an image, a title and description whenever a user posts a link from my web-app. I'm using Facebook's public-facing debugger to help me troubleshoot this.
But it is not working for me. Here is the state I'm using for my web-app's Splash Page:
$stateProvider.state('splash', {
url: '/',
templateUrl: 'html/splash.html',
controller: 'SplashCtrl',
data: {meta: {'title': 'XXXXXXXXXXXX',
'description': 'YYYYYYYYYYYY'}}});
Here is my controller:
myApp.controller('SplashCtrl', function($scope, ngMeta) {
var self = this;
console.log('self = ', self);
ngMeta.setTag('description', 'DDDDDDDD');
Here is my index.html
Here is my template file, splash.html which is referenced in the state declaration:
<div ng-controller="SplashCtrl as splashCtrl">
HELLO WORLD
</div>
Look what Facebook's debugger reports when I scrape this Splash Page (FYI, my private info has been scrubbed):
Why isn't the description I'm setting in SplashCtrl ('DDDDDDDD') showing up in Facebook's scraper? How can I fix it so it does?
BTW, I have successfully initialized ngMeta using the run() block. I know it's working because when I load this page, the <title>{{ngMeta.title}}</title> from index.html correctly shows up as AAAAA.
So ngMeta.setTitle() is definitely working. Then how do I set and access the other properties like description, image, etc?
All your meta tags are binding well, you can see it by inspecting your page
.
I think this facebook tools is reading the source code of your page instead of the initialised angular app(as if you do CTRL + U in chrome to see your source code, you will see that datas are not templating)
This does not matter for sharing content from your angular application. Facebook will take care to read the binding value instead of the scope variable
However if you want no scope variable from your source code,
This answer could be a solution

AngularJS mysterious error

I can't for my live figure out why Angular is not working along.
I defined a simple app and controller:
angular.module('weatherApp', [])
.controller("weatherController", function() {
console.log('weather controller created!');
});
In my HTML I have:
<div ng-app="weatherApp" ng-controller="weatherController"></div>
Nothing else. I'm using AngularJS 1.2.28 (constrained by the project I'm working with). Upon loading of the page, my console logs the expected text above. However, immediately following it is the following error:
Error: [ng:areq] http://errors.angularjs.org/1.2.28/ng/areq?p0=weatherController&p1=not%20a%20function%2C%20got%20undefined
Why is it doing this when it's (apparantly) working just fine?
When I'm not using a module or controller and simply define a global weatherController function, everything again works just fine.
I've looked around, but can't find anything about this being specific to 1.2.28 or something.
I figured it out! Apparently the ClientDependency was loading another app.js which does a lot more with AngularJS than my simple controller. The two simply couldn't co-exist!
Since I didn't need the other app in this particular page, I excluded it from the ClientDependency and voilá, fixed!

how to execute some function in every time page reload in AngularJs?

I am trying to execute function every time page reloads.
I used this, But its not working properly.
$(window).load(function () {
$rootScope.pageClass = "page-fadein-down";
});
How to do this angularjs or jquery?
Any help ?
You can use angular app.run() block. Angualr JS Module docs
Run blocks - get executed after the injector is created and are used to kickstart the application. Only instances and constants can be injected into run blocks. This is to prevent further system configuration during application run time.
myApp.run(['$rootScope', function($rootScope) {
$rootScope.pageClass = "page-fadein-down";
}]);

Uncaught Error: [$injector:modulerr] Failed to instantiate module with LABJS

I keep getting this error when loading my Angular app. In Chrome a couple refreshes and my app will run but IE and FF is a no go.
The error links me to this error page but I don't really understand what it says.
I am loading my app using LabsJS including the controllers and service.
// spAppLoader.js
$LAB
.script("../js/app.js").wait()
.script("../js/controllers/userCtrl.js")
.script("../js/controllers/groupCtrl.js")
.script("../js/controllers/siteCtrl.js")
.script("../js/services/userServices.js")
.script("../js/services/groupServices.js")
.script("../js/services/siteServices.js")
Markup:
<div id="mdContainer" ng-app="spApp" ng-cloak>
...
</div>
<script type="text/javascript" src="../js/spAppLoader.js"></script>
I wanted to post more code but I don't know where to start and with angular everything is in multiple files. I uploaded it through github.
You should manually bootstrap your app because you use an asynchronous script loader:
$LAB
.script("../js/app.js").wait()
.script("../js/controllers/userCtrl.js")
.script("../js/controllers/groupCtrl.js")
.script("../js/controllers/siteCtrl.js")
.script("../js/services/userServices.js")
.script("../js/services/groupServices.js")
.script("../js/services/siteServices.js")
.wait(function(){
var root = document.getElementById('mdContainer')
angular.bootstrap(root ,['spApp']);
})
What is bootstrapping?
angular.bootstrap(root ,['spApp']); is the same as <div id="mdContainer" ng-app="spApp"> only the last one would automatically initialize your app when DOMContentLoaded event occurs.
When using a script loader, DOMContentLoaded event might happen before all scripts are loaded, so you must wait for all your module scripts and then bootstrap your application manually.
In your case, chrome probably cached your scripts so after few refreshes the DOMContentLoaded event happened after all scripts were loaded.
From the docs:
Automatic Initialization
Angular initializes automatically upon DOMContentLoaded event or when the angular.js script is evaluated if at that time document.readyState is set to 'complete'. At this point Angular looks for the ng-app directive which designates your application root...
Manual Initialization
If you need to have more control over the initialization process, you can use a manual bootstrapping method instead. Examples of when you'd need to do this include using script loaders or the need to perform an operation before Angular compiles a page.
This error usually means angular can't find an object you are trying to inject into a controller or some other injectable function. After quickly looking through your code, my guess is that there is a problem with the way the files are being loaded, as you are referencing spApp from multiple files.
What I usually do is move separate files into their own modules, and then require other modules as needed. For example, instead of starting the userService like this:
spApp.factory('userService', function(){
put it into its own module
angular.module('spApp.services.user', [])
.factory('userService', function(){
Then whenever you need to use the userService in another module, add it as a requirement. Eg:
var spApp = angular.module('spApp', ['spApp.services.user']);

Force reload of a directive's template

I am working on an AngularJS app with several directives. The directive's templates are stored in a separate html file. When editing these template, my browser does not detect any changes after a reload and always uses a cached version. Any other changes to the source code are detected and lead to a reload.
I guess the problem is somewhat the $templateCache which seems to be used by AngularJS when loading the template.
What I found in the source code of AngularJS 1.0.2 is the following from line 4317 which is part of the compileTemplateUrl():
$http.get(origAsyncDirective.templateUrl, {cache: $templateCache})
I am wondering if anyone else had this kind of problem and if there is a way to tell AngularJS when to cache and when not.
I know this is an old question, but here's a simpler fix, although it's a bit of a hack, it works for me, and doesn't require you to do anything to $templateCache.
Whenever I run into this problem (I see it in directive templates, but also static JSON files), I add a query parameter to the end of the URL being loaded, like this:
...
templateUrl: "partials/template.html?1",
...
Whenever I make a changes to the template, and it's not reloading, I increment that number at the end. As the browser doesn't know if this might mean something special to the server, it should attempt to reload that changed URL whether it's cached or not. This will also make sure the file is reloaded in the production environment.
The template cache is stored in your browser, as this is a javascript app. You can actually feed the $cache manually or stop your browser from caching the templates (as it would seem that for production, cache won't be a problem), using developer tools.
For force feeding the cache:
function Main($cache) {
$cache.data['first.html'] = {value: 'First template'};
$cache.data['second.html'] = {value: '<b>Second</b> template'};
}
Main.$inject = ['$xhr.cache'];​
See it working in this fiddle.
To stop your browser from caching the templates (cited from this Google Groups post, about this problem, exactly):
My team and I have ran into this same issue. Our solution for
development while using Chrome was to open Developer Tools, and select
the gear in the bottom right hand corner. Then select Network -
Disable cache.
This fixed all our partial/template caching issues.
app.controller('someCtrl', function ($scope, $cacheFactory, templateRequest)
{
$scope.refreshTemplate = function ()
{
var tpl = "<template name>";
$cacheFactory.get('templates').remove(tpl);
$templateRequest(tpl).then(function ok(){
console.log("Template "+tpl+" loaded.");
});
}
...
}
then when you call the refreshTemplate function you cause a re-load

Categories

Resources