I'm trying to use AngularJS with Tippy.JS for tooltips.
Tippy's HTML template tooltip (#creating-html-templates) requires us to use style="display: none" for the template, and it handles the rest.
I want to use angularjs features in the tooltip template but failed.
Here is a fiddle which reproduces the problem. #fiddle
If you remove style="display: none" it works, but Tippy doesn't.
Is there any walkarounds for this?
Update
#Razzildinho solution works only to render the value. but it cannot communicate back to the controller. It is one-way data binding, model to tippy.
Inside Tippy:
Outside:
Fiddle
Using the element id as the html option removes all javascript bindings. To keep them use the DOM element. You should also append within the element that has your controller attached.
<!-- Add ID to the controller div -->
<div ng-controller="FrameController as vm" id="controller">
You also need to remove the display: none; from your template html. From the documentation:
If you want to clone the template's content into the tooltip, specify the template's id in the html setting. Otherwise use the DOM element itself, which allows you to keep listeners attached. If you use the DOM element choice, ensure it's not hidden with display: none;.
And then your javascript for tippy should be:
setTimeout(function() {
angular.bootstrap(document.getElementById('body'), ['app']);
tippy('.tippy', {
position: 'bottom',
animation: 'fade',
arrow: true,
interactive: true,
/* The following 2 lines are new */
html: document.getElementById('my-template-id'),
appendTo: document.getElementById('controller')
})
});
It's because the resulting html and widget is working outside angular scope. The same would happen if you try to implement boostrap widgets and add some angular behavior. That's why boostrap-ui exists, to bridge those two worlds.
The best way to workaround this is by creating directives that link your js pluging with angular. When doing the directive, you might need to recreate the plugin when the expression changes by setting a watcher on vm.message.
See this post as an example: http://bencentra.com/code/2015/09/29/jquery-plugins-angular-directives.html
Related
Is it possible to add a directive to DOM element using setAttribute()?
I was trying to implement drag and drop in my component with material drag and drop.
it is working, when i tried like this
<div class="example-boundary">
<div class="example-box" #test cdkDragBoundary=".example-boundary" cdkDrag>
I can only be dragged within the dotted container
</div>
from my understanding, drag functionality work through cdkDrag attribute directive.
When i tried to add this directive through setAttribute(), which is not working
constructor(private _renderer: Renderer2, private _elRef: ElementRef) {}
ngAfterViewInit(): void {
let requiredElem = this._elRef.nativeElement.querySelectorAll('.example-box');
this._renderer.setAttribute(requiredElem[0], 'cdkDrag', '');
}
When i checking the DOM, seems cdkDrag is added.
have any one to help me to sort this out?
thanks in advance.
Edit
I have implemeted that drag functionality in iframe element using jquery (https://stackblitz.com/edit/angular-ivy-syoi3w?file=src/app/iframe/iframe.component.ts) this slackBlitz example facing an issue with jqueryUi lib.
The simple answer is no, you can't do this in Angular. What you're looking for was possible in the old angular.js, by using the $compile service. For eg:
element.setAttribute('cdkDrag', '');
$compile(element)($scope);
But, for a number of good reasons, the Angular team decided to drop support for such dynamic approaches in the new framework.
In the first few RC versions of Angular, there were some workarounds/hacks based on DynamicComponentLoader that would allow one to achieve a dynamic directive compilation on DOM elements, but later DynamicComponentLoader was also deprecated and then removed.
I'm attempting to find the parent tr element when I use clicks a button on a datepicker calendar. Since I don't want to use jQuery in the form of a script tag (edit) in my Angular app, and this isn't possible using strictly CSS, I created the directive below. The elm.find is able to find and alter the css of the button correctly, so I know that I've found the element I'm looking for, however now I need to travel up the DOM.
I'm used to jQuery syntax, which doesn't work, and I haven't been able to find anything effective on the interwebs. Any chance someone could help me out with the syntax?
/* Linker for the directive */
var linker = function (scope, elm, attrs) {
elm.on('click', function() {
elm.find('table tbody tr button.active').parent('td').css('background-color', 'red');
});
};
EDIT
This is a directive that needs to be placed on a uib-datepicker element (Angular UI Bootstrap) in order to change alter the background-color for an entire row. The framework doesn't come with this functionality and the HTML isn't generated until the page loads.
I need to attach the directive to the element below, find the selected item and then work back up the DOM to find the parent tr.
<uib-datepicker highlightselectedrow class="well well-sm" ></uib-datepicker>
.parent will look exact the upper element only. I'd say that rather use .closest so it will search in parent till it gets td
elm.find('table tbody tr button.active')
.closest('td').css('background-color', 'red');
What about taking a more angular approach than psuedo jQuery? This is based on the ngStyle Angular doc:
<div ng-style="myStyle">Test</div>
<div ng-click="myStyle={'background-color':'red'}">Click Me</div>
You would then place the click event on whatever element you want (td). The ng-style can be moved to what you want affected (tr).
Like any normal person creating a web application using AngularJS, I initially tried using ng-hide/ng-show to make certain elements visible under certain conditions. For some reason, this doesn't want to work, and the code is too complex for me to recount it here. I figured it would be easy to use jQuery (or at least as much jQuery as Angular has built into it). This is what I have so far:
angular.element(document.querySelector([ELEMENT ID])).off();
The above line works for the purposes of hiding, but I can never get it back. In case you're wondering, I'm trying to hide buttons for otherwise unrelated actions. Using ".on()" for the code above doesn't work. How does this line need to be written in order for the element to disappear? More importantly, How do I make it reappear?
ng-show and ng-hide work with boolean values. Don't use jQuery inside the controllers. If you are needy to use that, create directives for that purpose.
Create flag variable in scope of controller. Set it to true or false
Now ng-show will show the element if it receives boolean value as true and will hide if it receives false.
Vice versa for ng-hide, it will hide if it received true and show if receives false.
So decide between either one of them, don't use both. So considering flag name is active and it is set to true and you want to show button in beginning. The code can be:
angular.module('demo', []).controller('DemoCtrl', function($scope){
$scope.active = true;
});
And the template will look like:
<div ng-app="demo">
<div ng-controller="DemoCtrl">
<button type="button" ng-click="active = false" ng-show="active">Hide Me</button>
<button type="button" ng-click="active = true" ng-hide="active">Reset</button>
</div>
</div>
We need a small css for this purpose:
.display-hide {
display: none;
}
Lets say there is an validation summary we are showing on the page;
<div class="alert alert-danger display-hide">
<button class="close" data-close="alert"></button>
<span>
#Html.ValidationSummary(false)
</span>
</div>
And with using jQuery;
jQuery(document).ready(function () {
#if(!ViewData.ModelState.IsValid) {
<text>
$('.alert span').parent().removeClass("display-hide");
</text>
}
else
{
<text>
$('.alert span').parent().addClass("display-hide");
</text>
}
});
You can use this trick for any html element.
on and off methods are not for showing/hiding elements but for adding and removing event listeners. I think by accident your element was already hidden and that led you to believe off hides element.
If you really can't use ng-hide/ng-show I suggest you use addClass and removeClass (instead of off and on) to add/remove 'hidden' class to your element. This class could would set the elements display to none.
However I encourage you to show the angular code so we can help you solve this using ng-show.
so here is the desire: I need to add a directive to any html element and pass it an id. This id is then used to populate a method that submits a form that has that id on the page.
Some devs have used a button some have used an anchor tag so I do not want the type of element to be part of the method. It is intended to be highly re-usable.
I already have it working like this:
angular.module("App").directive("submitform", submitFormDirective);
function submitFormDirective(){
return {
restrict: 'A',
scope: true,
link: function($scope, $element, $attrs){
var selector = $attrs.submitform;
$element.on('click', function(){
angular.element(selector).submit();
});
}
}
}
But this uses jquery for the "on" method. I want a fully angular method. Or one that does not "fight" with the framework or use jquery.
The way I am doing it now I only need to apply this attribute to the element. submit-form="#id-of-form" And I would like to keep that functionality becasue it is clean and concise. So I need to be able to add the ng-click to the element dynamically without using the limited template function which would limit the element being effected, inside the submitFormDirective.
The problem is that the $attrs.$set('ngClick', 'submitForm()') runs after the digest and $compile does not seem to work for me. I need to be able to add the click and run the compile on only this element or use a different phase that will happen before the app compile will run. But I have tried using compile to att the attr in conjunction with link adding the method to the scope to no avail. Seems strange that you would not be able to add a event from a directive. I must be missing something. Can someone help?
<div data-ng-controller="maincontrol">
<div class="main">
</div>
<button data-ng-click="submit()">click</button>
</div>
when i click on click button i want to append one div within main div . i want to append one new div (dynamically)for each and every click .also i want to find whether children div exist or not .
i will do like this in jquery
$('main').append();
i will pass div within append();
but how to do by using angular..js ?
Using a directive could be a solution, but it's still too close to jQuery. When you play with Angular, you have to think differently.
jQuery is procedural.
1- I am finding an element in the dom
2- I am doing some stuff
3- I am adding, removing, updating elements in the dom
angular is declarative
You define your data
You define how your data should be displayed (using ng-repeat, ng-class, etc..)
then..
when you are playing with your data, the view is automatically updating.
If you want to play correctly with angular you should maybe do something like:
Template:
<div class="main">
<div ng-repeat="stuff in stuffs"><h1>{{stuff.title}}</h1> <p>{{stuff.content}}</p></div>
</div>
Controller:
function MainCtrl() {
$scope.stuffs = [];
$scope.submit = function() {
$scope.stuffs.push({title: 'Hello', content: 'world'});
}
}
It's generally best to create a directive for DOM manipulation ( many other uses for directives also).
Within a directive you have access to the angular.element . If jQuery is installed before angular.js in page, this is a jQuery object, otherwise it is a jqLite object that has many jQUery compatible methods.
Very simple example:
<button data-ng-click="submit()" my-directive>click</button>
app.directive('myDirective',function(){
return function(scope, element, attrs){
element.click(function(){
element.parent().find('.main').append('<div>Some text</div>')
})
}
})
Read up on directives and angular.element