Dynamically loaded javascript of angular not working - angularjs

I am building an application where my DOM is add dynamically outside of angular world ie. jQuery and also the javascript for that is loaded dynamically. I get $compile from angular.injector method and also the scope and then did used the $compile service. But with all this my directives and controller don't run. I see them added to my app but still controller won't initiated.
index.html is
<html>
<head>
<script data-require="jquery#2.2.0" data-semver="2.2.0" src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="https://code.angularjs.org/1.5.8/angular.js"></script>
<script src="script.js"></script>
</head>
<body>
<div ng-app="test">
<div id="main">
</div>
</div>
<!--<script src="https://googledrive.com/host/0ByYZbKdhSDoSeFNQVGdEd2k3amM/direc.js"></script>-->
</body>
</html>
script.js
//Create angular module
angular.module("test",[]);
$(document).ready(function(){
//Load dynamically the JS
$.getScript('https://googledrive.com/host/0ByYZbKdhSDoSeFNQVGdEd2k3amM/direc.js', function(){
angular.element($("#main")[0]).scope().$root.$apply();
});
var scrip = "<script src=\"https://googledrive.com/host/0ByYZbKdhSDoSeFNQVGdEd2k3amM/direc.js\"></script>"
var htmlStr = "<span test-drective=\"test-drective\">Test</span>";
$("#main").append(angular.element('*[ng-app]').injector().get("$compile")(htmlStr)(angular.element($("#main")[0]).scope().$new(true)));
})
and direc.js is
angular.module("test")
.directive("testDrective", function(){
return {
restrict: 'A',
controller: function($scope) {
console.log("Controller")
},
link: function(scope, elem, attrs) {
console.log("link")
}
};
})
If I add the direc.js in index.html, all works fine but not with the dynamic load of script using jquery or added as part of dom.
Sample app:
https://plnkr.co/edit/gekifqGzJDAsWs5OF4ro

Try to bootstrap your angular app in code after you loading is completed and your DOM is ready angular.bootstrap(document, ['myApp']);
See bootstraping angular section "Manual Initialization"
In general all your javascript code of your angular app must be present at the client. And you should not manipulate the DOM outside directives. Perhaps this ng-bind-html-compile directive helps you to solve your problem in a more angular way

Related

Angularjs ui-router event

I have a page that uses angular ui-router to render two views on the same page.
I ultimately need to have this run under phonegap/cordova so will have to bootstrap angular to the elements on a deviceready event.
I managed to encapsulate the code into a function and when the function is called at the end of the page it works fine.
However when the same function is called on the window.onload or document ready event it fails to work. In fact if the function is called from the javascript console itself after page load it just fails to work.
Need help figuring out what is exactly going wrong.
Code below
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<script src="js/jquery-2.1.4.min.js"></script>
<script src="js/angular.js"></script>
<script src="js/angular-ui-router.min.js"></script>
<script>
</script>
</head>
<body>
<div ui-view="appview"> appview </div>
<div ui-view="msgview"> messageview s</div>
<script>
var routerApp;
var appViews = ['appview','msgview'];
function zero()
{
routerApp= angular.module('routerApp', ['ui.router']);
x=$("body").attr("ng-app","routerApp");
for(var i=0;i<appViews.length;i++)
{
angular.bootstrap($("#" + appViews[i]), ["routerApp"]);
}
routerApp.config(function($stateProvider, $urlRouterProvider)
{
$urlRouterProvider.otherwise('/messaging');
$stateProvider
.state('messaging',
{
url: '/messaging',
views:
{
'':{templateUrl:'http://geo.tikoo.com/app/components/messaging/phone/messaging.html'},
'msgview':
{
templateUrl: 'http://geo.tikoo.com/app/components/messaging/phone/messaging.html',
controller: 'messC'
}
}
});
});
routerApp.controller('messC', function($scope) {
$scope.username = 'Tom';
});
}
zero();
//window.onload=zero;
//$(document).ready(function(){zero();});
</script>
</body>
</html>
Figured it out after a few attempts.
Here is what needed to be done.
1. The routers need to be set first.
2. The attribute for ng-app on the element needs to be set next.
3. a angular.element(element).ready event needs to be caught to bootstrap
Understanding.
If the routers are not setup first then the bootstrapping fails (obvious)
The ng-app dynamic addition also needs the router setup (Interestingly chrome can work in any order but mobile browser/opera needs that router be setup first before the attribute ng-app is assigned to an element).
SET ROUTERS ==> ADD ng-app Attribute to element ==> Bootstrap
Hope this helps

Popovers without jQuery

I've been implementing popovers with AngularStrap and AngularUI Bootstrap. I can get both of these frameworks to get popovers working alongside the full jQuery library, but not when I exclude jQuery. I know that Angular includes a version of jQuery called jQlite, and supposedly that should be all you need to implement these other frameworks. Here's my question, is it even possible to implement popovers in Angular without the full jQuery library?
The first line of the ui-bootstrap homepage states:
This repository contains a set of native AngularJS directives based on
Bootstrap's markup and CSS. As a result no dependency on jQuery or
Bootstrap's JavaScript is required
AngularStrap's page doesn't mention any dependancy on jQuery either.
So, to answer your question, yes, you can implment the popovers without jQuery being included in your project.
I wasn't able to get the AngularUI popups working either, but was successful with Angular-Strap. I put together an example plunker that may help you out. I used something similar on my site.
Angular Strap popup directive (on Plunker http://embed.plnkr.co/lxL65Q/preview)
I'm using the popup for images. The 'image-popup' directive is placed in an img tag, where it expects a src attribute. Libraries I needed were the Bootstrap styles, Angular JS, and the Angular Strap script and template files.
<!DOCTYPE html>
<html ng-app="popupApp" ng-controller="AppCtrl">
<head>
<link data-require="bootstrap-css#3.3.1" data-semver="3.3.1" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
<link href="style.css" rel="stylesheet" />
<script data-require="angular.js#1.4.3" data-semver="1.4.3" src="https://code.angularjs.org/1.4.3/angular.js"></script>
<script data-require="angular-animate#1.4.3" data-semver="1.4.3" src="https://code.angularjs.org/1.4.3/angular-animate.js"></script>
<script src="//cdn.rawgit.com/mgcrea/angular-strap/v2.1.3/dist/angular-strap.js" data-semver="2.1.3" data-require="angular-strap#2.1.3"></script>
<script src="//cdn.rawgit.com/mgcrea/angular-strap/master/dist/angular-strap.tpl.js" data-semver="2.1.3" data-require="angular-strap#2.1.3"></script>
<script src="app.js"></script>
</head>
<body>
<h1>Using Angular JS and Angular-Strap to create a popup image viewer</h1>
<figure class="col-sm-4">
<img image-popup alt="lolcat" class="img-popup-source" src="http://obeythekitty.com/wp-content/uploads/2015/01/lolcat_flying_cat.jpg" />
<figcaption>Leaping Lolcats!</figcaption>
</figure>
</body>
</html>
The example app code looks like this:
// Include a reference to ngStrap like this
var popupApp = angular.module('popupApp', ['mgcrea.ngStrap']);
// This demo doesn't really need a controller but hey.
popupApp.controller('AppCtrl', ['$scope', function($scope) {
}]);
// Directive that displays an image within an Angular Strap popup.
// This directive should only be applied to an img, as it expects a 'src' attribute.
popupApp.directive('imagePopup', ['$popover', '$compile', '$window', function($popover, $compile, $window) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var myPopover = $popover(element, {
title: attrs.popupTitle,
template: 'angular-strap-popover-tpl.html',
html: true,
trigger: 'manual',
autoClose: true,
transclude: true,
scope: scope,
animation: 'am-fade'
});
// Toggle the popover closed when you click it
scope.closeMe = function() {
myPopover.toggle();
};
// Toggle the popover closed when you click the original smaller image.
element.on('click', function(element) {
myPopover.toggle();
});
},
// Isolate scope, load the popup template image's src from the src attribute of the original image
scope: {
popupImageSrc: '#src'
}
}
}]);
You may want to fiddle with the popup options and styles. Here's the popup template I used:
<div class="popover">
<div class="arrow"></div>
<h3 class="popover-title" ng-bind="title" ng-show="title"></h3>
<div class="popover-content" ng-click="closeMe()"><img ng-src="{{popupImageSrc}}"></div>
</div>
Angular Strap's components worked well for me, and they have a builder that lets you put together just the components that you need. I did have one challenge in testing this directive on my site though. I also use AngularUI (for the carousel) and there was a namespace collision on a 'tooltip' module shared by both libraries. I never did figure out how to work around that one.
I hope this is helpful, all the best.

templateUrl Not Working with in AngularJs Directives

This is my Index page
<link href="~/Content/bootstrap.min.css" rel="stylesheet" />
<script src="~/Scripts/angular.min.js"></script>
<script src="~/Content/efDirective.js"></script>
<script src="~/Content/EmployeeForms.js"></script>
<html ng-app="AngularModule">
<body>
<div employee-form></div>
</body>
</html>
This is DirectiveJs
var app = angular.module("AngularModule", []);
app.directive("employeeForm", function () {
debugger;
return {
restrict: 'EA',
//template: 'helloworld',
templateUrl: 'Content/efTemplate.html'
}
});
Content in efTemplate.html is not displaying on index.cshtml page.
Check the message in browser console, probably there will be some error message. Maybe the url to template is not correctly resolved?
Did you specify the base url for angular?
The other option is to pre-render the template directly in your html index file. That has the benefit of saving the extra http request.
Like this:
<script type="text/ng-template" id="templateUrl">
<h1>your template </h1>
</script>
Example here https://docs.angularjs.org/api/ng/directive/script

Bootstrapping AngularJS app dynamically

I have a problem with boostrapping an angularjs app - with initialization code in the controller. The simplified test-case is like this (index.js):
var myApp = angular.module( 'myApp', []);
myApp.controller( 'myAppController', [ '$scope', function($scope) {
console.log('never shown');
$scope.test = 'constructor called';
// removed more init code
}]);
$(document).ready(function(){
angular.bootstrap( document, ['myApp']);
console.log('Finished boostrapping.');
});
The HTML file for this test-case:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>TeST</title>
</head>
<body>
{{test}}
<script type="text/javascript" src="js/bower_components/jquery/dist/jquery.min.js"></script>
<script type="text/javascript" src="js/bower_components/angular/angular.js"></script>
<script type="text/javascript" src="js/index.js"></script>
</body>
</html>
The result is that console output only says "Finished bootstrapping" - and the controller function is never invoked. .. This baffles me a little, but this is my first angular 1.2 app. I get the same result If I put ng-app="myApp" in the tag and let angular bootstrap the app automatically. ...
you never set ng-controller anywhere in your markup.
also, you should either put your script tags in the head, or after </body>.
edit: when using bootstrap this way, the placement of the <script> tags goes matter.
The first parameter to the angular.bootstrap method is an element. Currently you are passing in document, which is not an element.
Try
angular.bootstrap(document.documentElement, ['myApp']);
or
angular.bootstrap(document.body, ['myApp']);

Talking to Angular Directive from Controller

I have a directive and I want to call a method of the Directive from outside controller . That means when I click a button in the main controller , I want to hide a component in the directive . Is this really possible ,If yes please help me .
Kamal
To call directive methods outside in a controller I would share a directive control object with the controller. Inside the controller you can call methods of this control object and they get executed inside your directive.
create a control object inside your directive
share this control object with the controller using tw data binding
call methods on this control object inside your controller
here is a plunker that demonstrates it: http://plnkr.co/edit/MqN9yS8R5dnqTfjqldwX?p=preview
You can accomplish this by allowing your directive to listen to a scoped property from your controller. Using isolated scope and the =, you can tell your directive what to pay attention to in order to hide its component:
Html:
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<script data-require="angular.js#*" data-semver="1.2.0-rc3-nonmin" src="http://code.angularjs.org/1.2.0-rc.3/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="Ctrl">
<h1>Hello Plunker!</h1>
<button ng-click="action()">Toggle</button>
<the-directive show-component="showIt"></the-directive>
</body>
</html>
JavaScript:
var myApp = angular.module('myApp', []);
myApp.controller('Ctrl', function($scope) {
$scope.showIt = true;
$scope.action = function() {
$scope.showIt = !$scope.showIt;
}
});
myApp.directive('theDirective', function() {
return {
restrict: 'E',
scope: {
'showComponent': '='
},
template: '<div><div ng-show="showComponent">show Me!</div></div>'
}
})
Here is a plunker demonstrating the technique.

Resources