Angular2 ng2-popover hide() is not working - javascript

app.module.ts
import { PopoverModule } from 'ng2-popover';
#NgModule({
declarations: [ ...],
imports: [PopoverModule],
providers: []
})
example.html
<a [popover]="customPopover" [popoverOnHover]="true" [popoverCloseOnMouseOutside]="true" href="www.google.com" (click)="$event.stopPropagation()" target="_blank">{{name}}</a>
<!--Popover content -->
<popover-content #customPopover title="{{name}}" placement="right"
[closeOnClickOutside]="true" [closeOnMouseOutside]="true">
<span class="popoverDesc">{{description}}</span><br /><br />
{{websiteLink | formatUrl:'text'}}<br /><br />
<button class="btn btn-secondary popoverBtn" (click)="toggleAddToListModalPopover($event)">Add to list</button>
</popover-content>
example.component.ts
import { PopoverContent } from 'ng2-popover';
#ViewChild('customPopover') customPopover: PopoverContent;
protected toggleAddToListModalPopover(e):void {
this.customPopover.hide();
this.showAddToListModal = !this.showAddToListModal;
e.stopPropagation();
}
I want hide the popover when modal opens. When I call the 'customPopover.hide()' function it gives me error:
error_handler.js:51 TypeError: Cannot read property 'hide' of undefined
at PopoverContent.hide (PopoverContent.js:78)
In 'PopoverContent.js' file there is line this.popover.hide(); but I have no idea how to initialize it. As my understanding is #ViewChild only initializes the class bind to #customPopover i.e. in my case popover-content. Can someone please give me a solution to initialize the 'Popover'?

I resolved it using below code i.e. add 'customPopover' as parameter in the function and call hide() method. I don't know if its a good way to resolve this or not?
example.html
<button class="btn btn-secondary popoverBtn" (click)="toggleAddToListModalPopover(customPopover, $event)">Add to list</button>
example.component.ts:
protected toggleAddToListModalPopover(customPopover, e):void {
customPopover.hide();
this.showAddToListModal = !this.showAddToListModal;
e.stopPropagation();
}

I think in your case, this.customPopover is undefined.
Other way you can hide your popover-content like this-
<div>
<popover-content #myPopover title="this header can be omitted" placement="right" [closeOnClickOutside]="true">
<b>Very</b> <span style="color: #C21F39">Dynamic</span> <span style="color: #00b3ee">Reusable</span>
<b><i><span style="color: #ffc520">Popover With</span></i></b> <small>Html support</small>. Click outside of this popover and it will be dismissed automatically.
<u (click)="myPopover.hide()">Or click here to close it</u>.
</popover-content>
<button [popover]="myPopover">click this button to see a popover</button>
</div>
See if this helps.

Related

How to dynamically add a component on link click in my Angular application

I have three components: (1) a navigation bar, (2) home page with a left and right div, and (3)view-associates. On link from the navbar, I want to dynamically add the view-associates component into the home's right div. I have already implemented the following code (in the traditional JavaScript fashion) into the navbar-component.ts file:
addTemplateTag(){
const link = document.querySelector('.nav-link');
const showArea = document.getElementById('showArea');
console.log(link);
console.log(showArea);
// check for specific class name to get appropriate template tag
if (link.classList.contains('view-associates')){
console.log('Found view-associates class in link. Getting tag...');
// NOTE: the below two lines did work BUT still did not show component
const templateTag = document.createElement('app-view-associates');
showArea.appendChild(templateTag);
}
}
Here is the HTML code with the navbar and home components, respectively:
navbar.component.html
<nav class="nav flex-column">
<a class="nav-link view-associates" (click)="addTemplateTag()">View My Associates</a>
</nav>
home.component.html (Before link click)
<div class="container-fluid">
<div class="float-left left">
<h1 class="title">Welcome</h1>
<app-nav-bar></app-nav-bar>
<button class="btn btn-primary logout-btn" (click)="logOut()">Log Out</button>
</div>
<div id="showArea" class="float-left right">
</div>
</div>
home.component.html (After link click)
<div class="container-fluid">
<div class="float-left left">
<h1 class="title">Welcome</h1>
<app-nav-bar></app-nav-bar>
<button class="btn btn-primary logout-btn" (click)="logOut()">Log Out</button>
</div>
<div id="showArea" class="float-left right">
<app-view-associates></app-view-associates>
<-- ^^^ appended but component not showing -->
</div>
</div>
Here's the images of the home page before and after the link click:
Before (with browser console)
After (with browser console)
This above code did work but still did not show the view-associates component at all. How do I resolve this issue? Any advice is appreciated.
Use ngIf and ngSwitch to show/ hide components dynamically. For example : -
in .html
<app-form></app-form>
<some-component *ngIf="isLoggedIn"></some-component>
<some-component *ngIf="!isWorking"></some-component>
<another-cool-component *ngIf="!isLoggedIn"></another-cool-component>
in .ts
export class MyFunnyComponent implements OnInit {
isLoggedIn = false;
cartValue: number;
constructor() {
}
ngOnInit(): void {
}
}
Obviously there are some other ways to handle these scenarios but, for the start it might be enough. We might also have to pass data from child to parent and vise versa.

Angular, how to use directive based on an boolean

I use a ngFor to show different button. I need to use a directive on different button but not all.
So I make this code :
<div *ngFor="let btn of btns">
<button {{ btn.useDirective ? 'appMyDirective' : '' }} ></button>
</div>
But I get this error
Error: Template parse errors:
Unexpected closing tag "button". It may happen when the tag has already been closed by another tag.
update you directive to be trigger base on state as an example consider this 👇
#Directive({
selector: '[appHello]'
})
export class HelloDirective {
#Input() appHello:boolean;
constructor(private elem: ElementRef, private renderer: Renderer2) { }
ngAfterViewInit() {
if (this.appHello !== false ) {
this.renderer.setProperty(this.elem.nativeElement, 'innerHTML', 'Hi 😎');
}
}
}
template
<div *ngFor="let btn of btns">
<button [appHello]="btn.useDirective">Hi </button>
</div>
if you set the value to be true the directive will work otherwise nothing will happen
demo 🔥🔥
Your syntax is invalid. To archieve what you want, do something like this:
<div *ngFor="let btn of btns">
<button *ngIf="btn.useDirective" appMyDirective></button>
<button *ngIf="!btn.useDirective"></button>
</div>
Try using below instead.
<div *ngFor="let btn of btns">
<button appMyDirective *ngIf="btn.useDirective"></button>
<button *ngIf="!btn.useDirective"></button>
</div>

Bootstrap tool tips look plain

Am trying to get a tooltip that has more styling than the plain text that a tool tip normally has.
I see that a Twitter Bootstrap tooltip is black, white text, has an arrow, etc.
My tool tips look like this:
I have read that to fix this I need to add this:
<script>
$(function () { $("[data-toggle='tooltip']").tooltip(); });
</script>
I did that and it has no effect.
The only thing I could possibly think might be affecting it is that this is an Aurelia application and I am doing this in a <template>.
Anything else I can be checking to see why this is not working?
Code:
<template>
<script src="myPathToJQuery/jquery#2.1.4/jquery.js"></script>
<script src="myPathToBootstrap/twbs/bootstrap#3.3.6/js/bootstrap.js"></script>
<button type="button" class="btn btn-default" data-toggle="tooltip"
data-placement="top" data-html="true" title="<b>Tooltip</b> <em>on </em> right">
Tooltip on right
</button>
<script>
$(function() { $("[data-toggle='tooltip']").tooltip(); });
</script>
</template>
There is small mistake in your code
ata-placement="top"
You missed D letter from data-placement, your code should be:
<button type="button" class="btn btn-default" data-toggle="tooltip" data-placement="top" data-html="true" title="<b>Tooltip</b> <em>on </em> right">
Tooltip on right
</button>
Instead of:
<button type="button" class="btn btn-default" data-toggle="tooltip"
ata-placement="top" data-html="true" title="<b>Tooltip</b> <em>on </em> right">
Tooltip on right
</button>
I got an answer from an Aurelia team member. This is what he said:
Bootstrap's tooltip component requires javascript. Use a custom attribute to execute the tooltip javascript
import {customAttribute, inject} from 'aurelia-framework';
import $ from 'jquery';
import 'bootstrap';
#customAttribute('bootstrap-tooltip')
#inject(Element)
export class BootstrapTooltip {
constructor(element) {
this.element = element;
}
bind() {
$(this.element).tooltip();
}
unbind() {
$(this.element).tooltip('destroy');
}
}
Then on the element, add the bootstrap-tooltip attribute:
<require from="./bootstrap-tooltip"></require>
<input bootstrap-tooltip data-toggle="tooltip" data-placement="top" data-title="bootstrap tooltip" title="html tooltip">
It works against the aurelia skeleton app. (I will work it into my typescript app.)

How do you stop an ember action from triggering on it's child elements / how to access events in actions

I know you can add bubbles=false to actions to stop propagation to parent elements, but how do you stop an action from getting called on it's child elements?
I'm trying to create an overlay to my site, which has a transparent background overlay-bg, a close button and some overlay-content. Each of these elements should be clickable to hide the overlay. But whenever I click the popup (which is restricted to a width of 400px inside the overlay-content) or the form elements inside the popup, etc... the hide method is still being called. The other actions on my form, etc are also being called at the same time.
My initial thought, a way I've done this with jQuery, is to use the event to determine if the clicked element has a class on it like canClose, so that if a child element is clicked the function would return before completion... but I can seem to figure out how to access an event object from the action. I tried returning this as a parameter of the action, but that just returns the ember component itself and not the element that was clicked.
Component:
App.OverlayComponent = Ember.Component.extend({
elementId: 'login-overlay',
// ...
actions: {
// ...
hide: function () {
var view = this;
view.set('showing', false);
view.$().one(Ember.$.support.transition.end, function () {
view.destroy();
});
}
},
});
Template:
<div class="overlay-bg" {{action 'hide'}}></div>
<a href="#" class="close" {{action 'hide'}}>×</a>
<div class="overlay-content" {{action 'hide' this}}>
<div class="popup">
<h1>Login</h1>
<form {{action 'login' on='submit'}}>
<label for="username">Username</label>
{{input value=username id="username" placeholder="Your email address" classNameBindings='usernameError:error'}}
<label for="password">Password</label>
{{input type="password" value=password id="password" placeholder="Password" classNameBindings='passwordError:error'}}
<button class="btn btn-primary" {{action 'login'}}>Login</button>
<p class="text-center forgot"><a href="#" {{action 'forgot'}}>Forgot Password?</a></p>
</form>
<hr>
<p class="mb0 text-center"></i> Login with Facebook</p>
</div>
<p class="text-center signup">Don't have an account? <a href="#" {{action 'signup'}}>Signup</a></p>
</div>
UPDATE:
Forgot to mention, I also tried adding e to my hide function and inside the handlebars helper in the template (hide: function (e) {} and {{action 'hide' event}}) but when I log e it's undefined.
Also, I'm using Ember 1.0.0... do I need to update to a newer version to get access to events in my actions?
I had this exact problem. I kept the action on the bg layer and removed it from the parent element, i.e.
<div class="overlay-bg" {{ action 'hide' }}></div>
<div class="overlay-content">...</div>
If you had the action on .overlay-content because it covers .overlay-bg, you may need
.overlay-content {
pointer-events: none;
}
.overlay-content > * {
pointer-events: all;
}

AngularJS toggle button

I am trying to create a toggle button in Angular. What I have so far is:
<div class="btn-group">
<a class="btn btn-primary pull-right"
ng-click="toggleArchive(true)"
ng-show="!patient.archived">Archive patient</a>
<a class="btn btn-danger pull-right"
ng-click="toggleArchive(false)"
ng-show="patient.archived">Unarchive patient</a>
.... some other buttons ....
</div>
Basically I achieve toggling, by having TWO buttons, and toggling between them. This is causing issues because the ng-hide just adds a display:none style to the button when it's hidden, which is causing me styling issues. Ideally I want to have ONE button, that has it's text, class and function call changed depending on the state of patient.archived.
What's a clean way to achieve this?
You should use ng-class to toggle between classes and bind the text with a regular Angular expression. Also, if your function toggleArchive only toggle the value, you can remove it and toggle the value from an Angular expression:
<a class="btn pull-right"
ng-class="{true: 'btn-primary', false: 'btn-danger'}[!patient.archived]"
ng-click="patient.archived = !patient.archived">
{{!patient.archived && 'Archive' || 'Unarchive'}} patient
</a>
for any other weary traveller...
you could simply have used ng-if. ng-if completely excludes the element from the DOM if false, so you'd have no issues with styles when not displayed. Also there is not really a need for the button group you could just change the text of the button
Something like this:
<button class="btn btn-primary pull-right"
ng-click="toggleArchive(true)"
ng-if="!patient.archived">Archive patient</button>
<button class="btn btn-danger pull-right"
ng-click="toggleArchive(false)"
ng-if="patient.archived">Unarchive patient</button>
It might help you:
<html>
<head>
<script src="js/angular.js"></script>
<script src="js/app.js"></script>
<link rel="stylesheet" href="css/bootstrap.css">
</head>
<body ng-app>
<div ng-controller="MyCtrl">
<button ng-click="toggle()">Toggle</button>
<p ng-show="visible">Hello World!</p>
</div>
</body>
</html>
function MyCtrl($scope) {
$scope.visible = true;
$scope.toggle = function() {
$scope.visible = !$scope.visible;
};
}
This may Help:
<!-- Include Bootstrap-->
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.13.3.js"></script>
<!-- Code -->
Click here to <strong>Toggle (show/hide)</strong> description
<input type="checkbox" class="toggle-button"
ng-model="patient.archived">
Then style the checkbox like a button.
if the toggle needs to do more things, add the following to your patient class:
class Patient {
constructor() {
this.archived = false;
}
...
get angularArchived() {
return this.archived;
}
set angularArchived(value) {
if (value !== this.archived) {
toggleArchived(value);
}
this.archived = value;
}
}
then use
<input type="checkbox" class="toggle-button"
ng-model="patient.angularArchived">
This is the simplest answer I've found. I haven't tried it with animations because I just use it for quick setup.
<a ng-click="scopeVar=scopeVar!=true">toggle</a>
<div ng-show="scopeVar">show stuff</div>
with scopeVar=scopeVar!=true undefined becomes true.

Categories

Resources