jQuery selectors not working inside AngularJS ng-view directive - javascript

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.

Related

Angular 1 how to properly include external component inside ng-include?

Situation: I have a view where I'm including a fragment with ng-include. The fragment loads perfectly and works as expected when inside view where controller is defined.
My problem is, that when I want to include external component inside the "ng-include" fragment "myView.html", it doesn't show up. When including it inside the main view where the controller is, it shows up and works as expected.
Main view:
<div ng-controller="MyController">
<div data-ng-include src="'views/myView.html'"></div>
<!-- When loaded here, the component shows up -->
<!-- <div id="componentDiv"></div> -->
</div>
Fragment "myView.html":
<div>
<div id="componentDiv"></div>
</div>
The component is loaded inside the "MyController", where "componentDiv" is the "id" of "div" where the component is placed:
var testObj = new TestObj({"container": "componentDiv"});
Trying to do this to be able to use this fragment with full functionality in several places.
Any ideas or suggestions what to look up or try?
IMHO I think that by saying "...to be able to use this fragment with full functionality in several places" you just answered your question. What you need is to build a custom directive and use it in any place you like.
see directive samples e.g. Angular documentation on directives

Is it possible to use JQuery includes with Angular Includes?

I am working on an application that utilizes both Jquery and AngularJS includes, however Angular does not seem to execute after Jquery has included a file that has AngularJS markup. Jquery is including the "top_nav.html" template and inside this template there lives a angluar ng-include calling cart.html". I need to figure out how to get the angular code to execute after being included by jQuery.
<div id="topNav"></div>
<script>
//outside the document ready statment
$('#topNav').load('includes/top_nav.html');
<script>
top_nav.html:
<div>
...
<div ng-controller="shoppingCart"
class="shopping-cart"ng-include="'includes/cart.html'"></div>
</div>
The jquery load does an ajax request. When the ajax is resolved, the angular have already been bootstrapped (assuming you use ng-app directive), so the html chunk that have been dynamically loaded was not bootstrapped by angular.
So, I guess that on the callback of the jquery load, you need to manually bootstrap angular passing <div id="topNav"></div> as the context. Something like this:
var topNav = $( "#topNav" );
topNav.load( "includes/top_nav.html", function() {
angular.bootstrap(topNav.find("> div")[0], ['topNavAngularModule']);
});
Note: I'm not sure, sorry, I haven't tested it, but I think it might only work if #topNav is located outside ng-app.

datepicker not opening in modal

I am new to AngularJS, building an application using AngularJS and RequireJS.
In one of the modules having a controller, I created a modal dialogue using $modal service. The modal dialogue has Angular Schema Form with Datepicker Addon.
Datepicker requires some script files to work. When I add those script files in index.html (main page) in the head section, it works within a dialogue box. But I can't change the main page, so I tried loading the dependencies in module file as shown in module.js but it does not work.
module.js
define(
[ angular, .../path to datepicker dependencies ],
function(angular) {
return angular.module("mainctrl", [])
.controller("test", function($scope,$modal) {
$scope.formOperation=function() {
$modal.open({
templateurl:../schema-form.html,
controller: modelCtrl
});
}
})
});
Below is the body section of the main page wherein if I add those script dependencies in head tag, datepicker works.
index.html
<body>
<div data-ng-view="" id="ng-view"></div>
<script src="bower_components/requirejs/require.js" data-main="../scripts/main"></script>
</body>
schema-form.html
<div class="modal-content h-widget-action-form">
<style>
#import url('/addons/h/widgets/h-action/h-action.css');
</style>
<div class="modal-body">
<!-- <i class="glyphicon glyphicon-remove pull-right" data-ng-click="cancel()"></i><br/>
<div data-ng-if="message" class="alert" data-ng-class="message.type">{{message.text}}</div> -->
<form novalidate name="formCtrl" sf-schema="definition" sf-form="form" sf-model="model"></form>
</div>
</div>
I checked the script tags appended by requirejs in index.html in head and it does contain all my datepicker dependencies in correct order (configured using shim), but still datepicker does not work until I specify those dependencies explicitly in the index.html head tag.
Could anyone tell me where I am going wrong?
My first thought was the datepicker component is not a module so define may not load it properly, have you tried wrapping it as a JavaScript module, it may be enough, it attaches itself to angular via
angular.module('schemaForm').directive('pickADate', function() { so it would need to be able to access angular in whatever scope it gets loaded obviously.
I assume you probably solved this already given the age of the issue.

Angularjs convert string to html in view

I am currently trying to add links in my view. I do have links which basically contains html tags as strings.
I tried:
<p data-ng-repeat='i in links' >{$ i.link $}</p>
which basically just deploy in my view : mylink
So I did try:
<p data-ng-repeat='i in links' ><span data-ng-bind-html="i.link"></span></p>
It doesn't work though, any idea how could I achieve this ?
Thanks.
Add the $sce as a dependancy of the module
angular.module('myApp', ['$sce']);
When getting the links
angular.forEach($scope.links, function(value){
value.link = $sce.trustAsHtml(value.link);
});
Using Safe Contextual Escaping (docs.angularjs.org/api/ng/service/$sce) and using trustAs delegate you're telling Angular that this value is safe to use within that context. In this example. $sce.trustAsHtml returns an object that angular can trust is safe to as HTML.
In the first case, you'll actually want to use:
<p data-ng-repeat='i in links' >{{ i.link }}</p>
Double braces, not brace-dollar. In the second case, ng-bind-html will require that you have added "ngSanitize" to your module's dependency list.
angular.module('yourAppNameHere', ['ngSanitize'])
Edit:
If you really do want clickable links on the page, then do pretty much what #sreeramu suggested (Though I'd see if you can't find a way to add a nice description):
<p data-ng-repeat='i in links' ><a ng-href="{{i.link}}">{{i.desc}}</a></p>
(Notice that he suggested using ng-href, instead of href. He's right.)
Insert ngSanitize as a dependency to you app:
angular.module('myApp', ['ngSanitize'])
But before be ensure that you are including the script angular-sanitize.js.
Good luck!
It might be that your links have already got the a tags with it so in this case you do not need to re-add the a tags...
In this case do this...
Add this to you scripts (include acc. to your angular version)
<script type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular-
sanitize.min.js"></script>
Add this to your app.js
var app = angular.module('modulename', [ 'ngSanitize']);
And than in your view do this
If it is the div that you want the link to attach to...
<div ng-bind-html="i.link"></div>
The above would give you something as this
<div><a href='your link'></a></div>

Stop Angular routing links inside ng-view

I'm using Angular JS to dynamically load content like so:
HTML
...
<div ng-controller="MainController">
<div ng-view></div>
</div>
</html>
Angular
(function(){
var app = angular.module('app', ['ngRoute', 'ngAnimate']);
app.config(function($routeProvider) {
$routeProvider.when('/test', {
templateUrl : 'views/test.html',
controller : 'MainController'
});
});
app.controller('MainController', function($scope){ });
})();
This works as expected. However, inside the file test.html I have some links with the href="#" that need to be handled with javascript to do various things. At the moment, Angular is interpreting them with it's routing method and treats them as links to the homepage. How do I stop this and treat the links the way I want?
Example test.html content:
Left
Right
<p>Test content</p>
In a JS file separate from Angular I tried:
$('.slideLeft').on('click',function(){
return false;
});
But it doesn't do the return false, it uses the Angular routing.
You should be using Angular for all your bindings including event bindings. Don't use .on('click'), use ng-click (or .bind if you really need it, but you probably don't).
You can also see from the docs that the <a> directive does nothing if href is empty. Use href="" rather than href="#"
Use href="javascript:void(0)" in anchor attribute and also you should use ngClick instead of binding element using jQuery.

Categories

Resources