AngularJS: initialize ZURB Foundation JS - javascript

I am using both AngularJS and Foundation.
To initialize Foundation JS, you have to make the following call:
$(document).foundation();
What would be the best way to make this call in an AngularJS application? Code examples would be appreciated.
Also, if I were to write a directive around a Foundation JS component, how could I ensure that Foundation is initialized?

Here is my take, in app.js:
.run(function($rootScope) {
$rootScope.$on('$viewContentLoaded', function () {
$(document).foundation();
});
});
which will re-initialize Foundation when a new view is loaded (so that the components contained in the new view are also initialized). This way, your controllers do not need to be aware of this.

You could $apply the code in order to bring it into the Angular framework. Here is an example using $rootScope with run and this could also be done inside a controller/directive with any $scope:
app.run(function($rootScope){
$rootScope.$apply($(document).foundation());
});
Another option::
$compile($(document).foundation())($scope);
Be sure to include the $compile service in your controller/directive to use it this way. E.g.:
app.directive('mydirective', function($compile) {
return {
link: function(scope, element, attrs) {
$compile($(document).foundation())(scope);
}
}
});

There is a native angularJs support for foundation. Check out Angular Foundation.
Angular Foundation is a port of the AngularUI team's excellent angular-bootstrap project for use in the Foundation framework.
It has no dependencies but angular library itself and foundation CSS only.

One method that I've been using is to just include a <script> tag at the end of my partial / template.
This way, I can target just the new content of each partial -- instead of making foundation js re-parse the whole DOM.
for example, in my header.html:
<header id="app-header">
<h1>Logo</h1>
<dl class="accordion" data-accordion>
<dd>
Panel 1
<div id="panel1" class="content">
Loren Ipsum blah blah blah....
</div>
</dd>
</dl>
</header>
<!-- add this tag on bottom of template / partial -->
<script>$('#app-header').foundation();</script>
Especially if your app has a lot of DOM elements on the page, this can improve perfomance considerably.

Try the following code:
app.run(function($timeout){
$timeout(function() {
$(document).foundation();
}, 500);
});
It solved my issue trying to get Foundation reveal working.

For TypeScript Angular 4 (or 2) projects using Components:
According to the given blog post, declare $ as a variable in the component and then call $(document).foundation(); in ngOnInit() worked for me!
With Angular, components are injected into the DOM after Foundation
has loaded. When you load up a new component, and inject it,
Foundation doesn’t know it’s there. We need to tell Foundation to
reinitialize and bind again, so these attributes will get wired up. http://justindavis.co/2017/06/15/using-foundation-6-in-angular-4/
{ import Component } from '#angular/core';
declare let $: any; // TO ACCESS JQUERY '$' FUNCTION
#Component({
selector: 'my-component',
templateUrl: './my-component.html'
// other stuff here
});
export class MyComponent implements OnInit {
constructor() {}
ngOnInit() {
$(document).foundation(); // CALL foundation() INITIALIZATION FUNCTION FROM HERE
}
}

Related

Dynamically update AngularJS component definition

I'm looking for a way to dynamically update a component, I have an object containing the information about the component (name, functions, variables, services, template, bindings, etc.). Then I generate the component dynamically using this data. And I need to regenerate the component whenever the definition is changed.
angular.module('components', [])
.component('dynamicComponent', {
bindings,
template,
controller
})
angular.module('app', ['components'])
Is there a way to update the component that has been already registered on a module? or is there a way to update the module itself?
so far I've tried recreating the components module like so:
angular.module('components', [])
.component('dynamicComponent', {
...newData
})
but nothing happens.
I also tried recompiling the element after I recreated the module. Still nothing happens.
I also tried calling angular.bootstrap after creating the modules but I found out that is not possible without destroying the element bootstrapped. It's throwing an error saying the element was already bootstrapped.
My goal here is to dynamically update the component definition, on the fly, without reloading the page.
I was able to do this by destroying the bootstrapped element, recreating that element, and calling angular.bootstrap again with the new updated modules and components.
Here's an example,
The initial code:
<body>
<div id="app" ng-controller="MainController as $ctrl">
<dynamic-component data="$ctrl.data">
</dynamic-component>
</div>
</body>
angular.module('components', [])
.component('dynamicComponent', {
bindings: {...},
controller,
template
})
angular.module('app', ['components'])
.controller('MainController', ...)
angular.bootstrap(document.querySelector('#app'), ['app'])
And to update dynamic-component,
reset and destroy the bootstrapped element. Doing so will enable us to call angular.bootsrap on this element again
document.body.innerHTML = `
<div id="app" ng-controller="MainController as $ctrl">
<dynamic-component data="$ctrl.data">
</dynamic-component>
</div>
`
Define your modules.
Here, we can update the old dynamic-component however we want to. We can also add more components or modules.
angular.module('components', [])
.component('newDynamicComponent', {
bindings: ...newBindings,
controller: newController,
template: newTemplate
})
angular.module('app', ['components', ...otherModules])
.controller('MainController', ...)
angular.boostrap(document.querySelector('app'), ['app'])
Working example
If there's a better way, please let me know.

jQuery selectors not working inside AngularJS ng-view directive

If I put this:
<button type="button" class="btn btn-info" data-toggle="tooltip" data-placement="top" title="Tooltip on top">
Tooltip on top
</button>
Inside the index.html file, just between the <body> tags, it works -
I got the tooltip shown as it should be.
But If i put the same thing in a directive of ng-view - like this:
<div ng-view></div>
The button is shown but the tooltip is not get fired.
The ng-view contains another html template file, using the ngRoute module which contains the <button> tag as specified above.
It seems like jQuery cannot select elements that are located inside the AngularJS ng-view directive.
How could this be solved?
jQuery can and does select the button. However, AngularJS's digest loop is likely removing the tooltip content from the DOM. Outside of the element that hosts the AngularJS application, this does not apply (no pun intended). Furthermore tooltips popovers are added asynchronously.
To make AngularJS recognize the change
import $ from 'jquery';
import 'bootstrap';
import angular from 'angular';
run.$inject = ["$scope"];
function run($scope) {
const tooltippedElements = $('[data-toggle="tooltip"]');
tooltippedElements.on('hidden.bs.tooltip', onShownOrHidden);
tooltippedElements.on('shown.bs.tooltip', onShownOrHidden);
function onShownOrHidden() {
if (!$scope.$phase()) {
$scope.$apply();
}
}
}
angular
.module('app', [])
.run(run);
But instead of going through all of thirs trouble, use
angular-ui-bootstrap or something similar.
I have found the answer:
jQuery selectors, like $('[data-toggle="tooltip"]').tooltip(); are getting actioned before ng-view is getting actioned.
Therefore tooltip selector is trying to select an element which is not already been loaded to the DOM.
The solution for this problem, is simple:
Include jQuery before AngularJS scripts in the index.html file (at the end of the body tag).
Add ng-if directive to each jQuery script that has selectors (but not to the main jQuery file), like this:
<script src="assets/js/scripts.rtl.js" ng-if="initSrc"></script>
Set $rootScope.initSrc=true after any directive/component is loaded.
All of the jQuery functions will be working properly.

My page turns blank when I try to use a controller in angular

I have a problem with angular to integrate a controller to my page. The page becomes blank as soon as I try to integrate it.
<div class="container-fluid" ng-app="ods-widgets" ng-controller="myCtrl" >
<ods-dataset-context context="cont" cont-domain="https://data.rennesmetropole.fr" cont-dataset="{{dataset}}">
</ods-dataset-context>
</div>
<script>
var app = angular.module("ods-widgets", []);
app.controller("myCtrl", function($scope) {
$scope.dataset= "statistiques-de-frequentation-du-site-rennes-metropole-en-acces-libre";
});
</script>
Without the controller:
http://jsfiddle.net/5c0xr8f4/13/
With the controller:
http://jsfiddle.net/8796ueyL/
ods-dataset-context is a component (https://github.com/opendatasoft/ods-widgets).
it's a component that I import via CDN.
I just want to control what is inside the cont-dataset
I looked into the library that you mentioned in your comment. It seems that the issue is that ods-widgets is already an angular module that is being imported via the CDN. If you name your own angular module with the same name, you are effectively overwriting this existing module that you have imported. So what you want to do is declare your own angular module and import ods-widgets as a dependency. You can take a look at the Fiddle for a working sample, but the important part is this one:
angular.module("myApp", ['ods-widgets']);
And in your HTML update the ng-app reference:
<div class="container-fluid" ng-app="myApp" ng-controller="myCtrl" >

converting Jquery to angular or making Jquery work in angular

I am new to angular and we are converting a set of screens based on jsp to angular. Initially we have written lot of code in Jquery. Converting them to angular is tedious task and thought of trying to see if we can make jquery work with angular. Here is teh code snippet that i am trying to make it work while it in Jquery.
$(document).ready(function() {
$("#ClickTask2").click(function() {
$(".ClickTask1").hide();
$(".ClickTask2").show();
});
});
Above is the piece of code I have in JQuery and i tried to make it work.
angular.element(document).ready(function() {
$("#ClickTask2").click(function() {
$(".ClickTask1").hide();
$(".ClickTask2").show();
});
});
Can anyone tell me how i could make it work with minimal changes to the above one and rest of the jqueries?
You can convert many jquery features over to Angular by simply changing the $() method to angular.element() e.g.
$('#output').html('<h1>Title</h1>');
You could convert this to:
angular.element('#output').html('<h1>Title</h1>');
However not all function work, and some are renamed e.g.
$("#output").click(function() { console.log('Hi'); });
Would need to be changed to:
angular.element('#output').on('click', function() { console.log('Hi'); });
You can find a full list of the supported functions here:
https://docs.angularjs.org/api/ng/function/angular.element
like said Luis Masuelli on the comments read the basis of Angular. a quick lesson
app.js
function TaskCtrl($scope) {
$scope.selectedTask = null;
$scope.tasks = [/* ... */];
$scope.onClickTask = function(task) {
$scope.selectedTask = task;
}
$scope.isSelected = function (task) {
return task === $scope.seletectedTask;
}
}
$scope it is a special variable, it is injected by Angular to controllers and serves to communicate the controller with the view among other things. A controller can be any function and the name does not matter.
main HTML
<ul data-ng-controller="TaskCtrl">
<li data-ng-repeat="task in tasks" data-ng-click="onClickTask(task)">
{{task.title}}
<div data-ng-show="isSelected(task)">{{task.description}}</div>
</li>
</ul>
data-ng-controller tells to Angular "this is the controller" for this tag and her children. The other directives are pretty explanatory, but the documentation you left it more clearly.
Of course I am assuming that your tasks has the following structure:
{
title: "...",
description: "..."
}
in your html you need include the angular.js, the previous js and a directive to tell angular that this is a application
<!DOCTYPE html>
<html>
<head></head>
<body data-ng-app>
<!-- main HTML -->
<script src="angular.js"><script/>
<script src="app.js"><script/>
</body>
</html>
the data- prefix on each directive is not necessary but as angular "extend" HTML and these are not native attributes, I use them to place custom attributes as "ng-repeat", "ng-controller", "ng-app" etc. They are called directives
Remember, with Angular you need not manipulate the DOM directly as is done with jQuery, except for some special exceptions

Embedding AngularJS in existing jquery/bootstrap based website

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;
};
}
};
}
]);

Categories

Resources