I have an AngularJS app which (reduced to relevant parts) looks like this:
<div ng-app="myModule">
<div id='container'>
<div say-hello-to name="Frank">f</div>
<div say-hello-to name="Billy">b</div>
</div>
</div>
the application works fine. Now, if after the angular bootstrapping process, I add a new dom element, which corresponds to a directive, it isn't interpreted. Note that the "Addition" is done by non-angularjs JavaScript Code.
<div say-hello-to name="Dusty">d</div>
it is just "dead" div.
JsFiddle Link: http://jsfiddle.net/Nn34X/
The question is: How can I add a new DOM Element into the application and let AngularJS know that there is a new Element to be interpreted (I could easily point angularjs exactly to all inserted elements)
Cheers, and thanks in Advance!
Retrieve the $injector service:
var $injector = angular.element(document.querySelector('#container')).injector();
Select the element:
var element = angular.element(document.querySelector('[name="Dusty"]'));
Use the $injector service to retrieve the $compile service and link the element to the scope:
$injector.invoke(function ($compile) {
var scope = element.scope();
$compile(element)(scope);
});
Demo: http://jsfiddle.net/6n7xk/
Short explanation: Call Angular JS from legacy code
Related
I am using node and angularjs. I have a frame like page inside an ejs that is passed content to load into the includes dynamically.
<div ng-app="thisApp">
<div ng-controller='MainCtrl'>
{{ firstMessage }}
<div id='contentFromNode' ng-include='<%= pageContent %>'></div>
</div>
</div>
<script>
var thisApp = angular.module('thisApp', []);
thisApp.controller('MainCtrl', [ '$scope', function($scope) {
$scope.firstMessage = "Main Controller Working Fine";
}])
</script>
and then the passed content might be just an html page containing something like this:
<div ng-controller='NestedCtrl' id='content-type-container'>
{{ nestedMessage }}
</div>
<script>
thisApp.controller('NestedCtrl', [function(){
var nested = this;
nested.nestedMessage = "Nested Won't Work";
}])
</script>
So I have tried $scope within the NestCtrl instead of referencing this, I have tried moving the script tag above and below (ideally this get separated eventually anyway). I have tried aliasing the controllers, however my problem is the in registration of the controller itself as I get that great Error: [$controller:ctrlreg] error. The page is loading the content fine? Any ideas what I am doing wrong here?
Seems JQlite doesn't support this. You have to include jquery or lazy load the script. Refer
AngularJS: How to make angular load script inside ng-include?
We are working with jquery 1.9.1 and angular 1.2.13. We are using a wysiwyg editor that works great, we save the html into the database and load the html back using jquery append function and works fine. Now we are trying to append the same html into a div tag (the wysiwyg editor also uses a div) and the append function it's not working. We check in the console, and the string we are trying to append is there, also jquery grabs the element (also checked in the console log) but the append function it's not working.
PD: I apologize for my english
The html
<div data-ng-controller="PreviewCtrl">
<div class="container">
<div id="resumenPreview"></div>
</div>
</div>
The controller
angular.module('module').controller('PreviewCtrl', ['$scope', '$routeParams', '$location', '$http', 'selectedElement',
function ($scope, $routeParams, $location, $http, selectedElement) {
$scope.id = $routeParams.id;
$scope.mensaje = $scope.id;
$scope.imagen = null;
$scope.dataImagen = null;
//is not working either
$('#resumenPreview').append("hola");
$scope.pageLoad = function () {
var x = selectedElement.data.Resumen;
//This is properly displayed in the console
console.log(x);
//This too, is displayed in the console log
console.log($('#resumenPreview'));
// Why this isn't working? I'am clueless
$('#resumenPreview').append(x);
};
$scope.pageLoad();
}]);
My guess would be there are multiple divs with id="resumenPreview". But this is clearly the wrong way to handle such things in angular. There shouldn't be dom-manipulation in the controller - directives should take care of dom-related stuff. Put the html-string into the scope and let angular handle the injection into the dom:
instead of $('#resumenPreview').append(x); do $scope.resumenPreview = x;
and in the template do this:
<div class="container">
<div ng-bind-html="resumenPreview"></div>
</div>
Solve it with angularjs for the ng-bind-html to work it's necessary to include
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular-sanitize.js"></script>
and to add 'ngSanitize' as a dependency in the app module configuration. And then just do what #Johannes Reuter posted.
Thanks everybody, Greetings.
I'm working on porting a jQuery plugin to AngularJS just because it seems fun.
In the past, when using jQuery, I was using jQuery to manipulate the DOM. So, I have a function in jQuery to load the plugin and in that function is was maniuplating the DOM.
Now, when using AngularJS, I've read that there are directives for that specific purpose, but I don't manage to find the solution.
I have the following html:
<body class="officeui-space-no-margin officeui-space-no-padding">
<!-- Defines the OfficeUI section. In this section, all the contents for the OfficeUI user interface will be written. -->
<div ng-controller="OfficeUIController" id="OfficeUI">
<div class="title officeui-align-center">
<span>Here the title can go.</span>
</div>
<!-- Defines the main holder for the ribbon. -->
<div id="ribbonHolder">
<!-- Render the template for the ribbon. -->
<ng-include src="'Partials/Templates/Ribbon/tabs.html'"></ng-include>
</div>
</div>
<!-- Bottom scripts: Used for Initialization. -->
<script type="text/javascript">
// Initialize the 'ribbonHolder' element as a ribbon.
$('#ribbonHolder').ribbon();
</script>
</body>
You see here that I'm loading a template to render, of which the contents can be found below:
<ul role="tablist" class="officeui-space-no-margin officeui-space-no-padding">
<!-- Render all the tabs in the collection. -->
<tabs-container>
<li role="tab" class="officeui-display-inline-block officeui-align-center" ng-repeat="tab in tabs">{{tab.Name|tabs}}</li>
</tabs-container>
</ul>
In the template above, I do have an element tabs-container which should be my directive.
I've the JavaScript that defines the AngularJS stuff, including registering this directive:
var officeUIApplication = angular.module('OfficeUI.Ribbon.Controllers', []);
officeUIApplication.directive('tabsContainer', function() {
var functionLink = function(scope, element, attrs) {
console.log(element.children());
};
return {
restrict: 'E',
link: functionLink
};
});
According to my very limited knowledge of AngularJS, I'm just learning it, it's in the variable functionLink where I should manipulate the DOM of attach event handlers to specific parts.
But inside functionLink I call the following code:
console.log(element.children());
But in the console I do see that this particular element is empty.
Why is that, and is this the good approach?
Another approach of which I've tought it to include something in jQuery so that the code is only executed after AngularJS has finished it's work, but I don't like that particular idea, on the other hand, how do I create a jQuery plugin that that passes options and event handlers, or isn't that possible anymore and am I in fact creating an AngularJS plugin?
Thanks for the response.
Try this:
officeUIApplication.directive('tabsContainer', function($timeout) {
var functionLink = function(scope, element, attrs) {
$timeout(function() {
element.ribbon();
});
};
return {
restrict: 'E',
link: functionLink
};
});
jQuery plugins usually require the DOM to be ready for it to initialize properly. In angular, there is no real concept of DOM ready. $timeout is executed after the render phase, which is why it works.
We've got an existing application where the client-side is jQuery / Bootstrap. It consists of many tabs where each tab is defined in a module imported via. require.js. The tab javascript is handed a parent DOM element and is in charge of drawing itself inside of that element.
We'd like to start building new functionality (tabs) in AngularJS and running into some problems doing that.
My thinking is that we could tag the body with ng-app and in the main page code conjur up an app module window.app = angular.module('ourApp', []); and later, as tabs are loaded, create and wire-up the controllers.
I've built a simple single-page example that exhibits the problem we are having (below or here http://jsfiddle.net/p4v3G/1/).
The only way I've been able to get the example to work is manually calling angular.bootstrap which I'm pretty sure is wrong. Also, that only works the first time so if I click the button twice (equivalent to navigating to the tab, away from it, and back again within our app), Angular isn't wired up properly.
I'd appreciate any help.
<body ng-app='testApp'>
<div id="main" style="border: 1px solid #000; background: #ffdddd;">Click button to replace template and wire up controller...</div>
<button id="button1">Load</button>
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.14/angular.min.js"></script>
<script>
var app = angular.module('testApp', []);
jQuery(function() {
$("button").click(function() {
// controllers are wired up in click handler to simulate environment where we
// are looking to embed angular inside of an existing bootstrap/jquery application
// where new tabs (loaded as separate modules through require) are loaded on-demand.
app.controller('TestController', function($scope) {
$scope.message = 'Hello World, from Controller #1';
});
$("#main").html('<div ng-controller="TestController">{{message}}</div>');
// Bootstrap works the first click but not subsequent clicks
angular.bootstrap(document, ['testApp']);
});
});
</script>
</body>
To chunk up your appliation so that only the relevant parts are instantiated etc. what you need is angular ui-router. You would then set up a parent state for your tab-control with child states for each of your tabs. That way you both get deep linking and the performance you want with loading only the relevant tab.
As for requirejs, I encourage you to firstly consider if you really need it. In my opinion the javascript making up an angular application is usually much terser than a jquery application due to the declarative nature of the technology. Therefore loading all of the javascript at boot-time is ok. Your templates however may not be as simple, but by using templateUri references to templates they may be loaded as needed. (Personally I prefer compiling them to javascript and placing them in the $templateCahce at the cost of boot-time, but that's another matter.)
That being said, if my observations do not hold for your scenario/application/codebase, then others have had great success incorporating requirejs with angularjs. For a nice introductory talk on that subject see this nice ng-conf video.
Best of luck!
Could you be more precise, what type of errors appears.
You don't need use jquery. Check this code and compare
http://jsfiddle.net/pokaxperia/3w6pb/1/
HTML
<body ng-app='testApp'>
<div ng-controller="TestController">
<span id="main" style="border: 1px solid #000; background: #ffdddd;">{{message}}</span>
<button ng-click="loadMessage();" id="button1">Load</button>
</div>
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
</body>
script
var app = angular.module('testApp', []);
app.controller('TestController', ['$scope',function($scope) {
$scope.message = "Click button to replace template and wire up controller...";
$scope.loadMessage = function(){
$scope.message = 'Hello World, from Controller #1';
};
}]);
Or check your code on jsfiddle, but with few variants
http://plnkr.co/edit/fUQDpO?p=preview
HTML
<body>
<example-tabs></example-tabs>
<div class="panel" ng-show="isSelected(1)">Panel One</div>
<div class="panel" ng-show="isSelected(2)">Panel Two</div>
<div class="panel" ng-show="isSelected(3)">Panel Three</div>
</body>
Main script:
var app = angular.module('tabsExample', ['tabDirectives']);
Directive to load Tabs
var app = angular.module('tabDirectives', []);
app.directive('exampleTabs', [
function() {
return {
restrict: 'E',
templateUrl: 'example-tabs.html',
controller: function($scope) {
$scope.tab = 1;
$scope.selectedTab = function(setTab) {
$scope.tab = setTab;
};
$scope.isSelected = function(checkTab) {
return $scope.tab === checkTab;
};
}
};
}
]);
I am trying to use Waypoints inside a scrollable AngularJS view, however it's not working. I am trying to use ui.utils jQuery Passthrough but nothing happens. Here's what I have so far:
<body>
<div id="wrapper">
<div id="nav-menu">
<...>
</div>
<div id="main" class="main">
<div ng-view></div>
</div>
</div>
</body>
I am using the following template for the view:
<div class="fullScreenImage"></div>
<div ui-jq="waypoint" ui-options="test">test</div>
and my controller looks something like this:
app.controller('myController', ['$scope',
function ($scope) {
$scope.test = function(){
alert('You have scrolled to an entry.');
}}]);
My main element is scrollable but the window is not. Setting passthrough to the main div will trigger the test function, however I need it inside the template. Any suggestions?
Providing a JSFiddle or plunkr would be helpful.
But I suppose the issue is because the template is inside ngView.
As the content of the template is placed inside the ngView via XHR, the waypoints needs to be refreshed as discussed in the link http://imakewebthings.com/jquery-waypoints/#doc-refresh
An Angular directive will be more effective IMHO.
I had trouble with waypoints nested in ng-views as well.
My solution was just to wait till after the view had loaded to bind the waypoints, for this you can use $viewContentLoaded.
E.g.
myApp.run(['$rootScope', function($rootScope) {
$rootScope.$on('$viewContentLoaded', function(){
var waypoint = new Waypoint({
element: document.getElementById('waypoint'),
handler: function(direction) {
console.log('Scrolled to waypoint!')
}
})
});
}]);
I had the same problem. It's also possible to delay the binding with $timeout e.g $timeout(addWaypoints());.