How to pass class through an Angular Custom component - javascript

So I have a tooltip custom component that I need to be able to pass a class through to the underlying html, but not sure how to do it. Currently the tooltip (custom angular component) html looks like this:
<div role="tooltip" aria-haspopup="true" class="tooltip tooltip-md tooltip-bottom-right">
<clr-icon class="icon-shape is-solid" shape="info-circle" size="20"></clr-icon>
<div class="tooltip-content">
<ng-content></ng-content>
</div>
</div>
Using this custom component is like:
<tooltip>This is the text displayed.</tooltip>
What I need to be able to do is pass in a position so that the tooltip isn't always at bottom-right. So I need to pass either a property or class or something so that in the custom component I can change the class of my div to "tooltip-top-right", "tooltip-bottom-left", etc... like so:
<tooltip class="tooltip-bottom-left">Tooltip text</tooltip>
or
<tooltip position="bottom-left">Tooltip text</tooltip>
And then inside the component's .ts or .html, assign the appropriate class to my div.
Thanks in advance!

You could use mat-tooltip for this case.
https://material.angular.io/components/tooltip/overview
It has built in matTooltipPosition directive so you wouldnt need to add any class to it.
1) Import the appropriate module in app.module.ts
import {MatTooltipModule} from '#angular/material/tooltip';
2) Use the mat-tooltip selector and the matTooltipPosition input property
<button mat-raised-button
matTooltip="Info about the action"
[matTooltipPosition]='where you want it to be'
aria-label="Button that displays a tooltip when focused or hovered over">
Action
</button>
more examples:
https://material.angular.io/components/tooltip/examples

Related

How can I style the arrow of react-multi-select-component?

I'm looking to customize the downward arrow icon in the react multi-select component. In the documentation, there is an attribute ArrowRenderer which takes reactNode as a value.
How to configure this to customize the styles?
Dropdown looks like:
Any help would be highly appreciated
Put your react node in div tag with specific class(Name) and then access that class by css selectors.
<MultiSelect
arrowRenderer={()=>
<div className="custom-arrow" >
<CustomArrowComponent />
</div>
}
/>

How to pass ref from parent to child component in template

I am using this component https://element.eleme.io/#/en-US/component/popover
Issue related to triggering element (it is used to calculate where is popover located)
For the triggering element, you can write it in two different ways: use the slot="reference" named slot, or use the v-popover directive and set it to Popover's ref.
Everything ok with default examples. But I am using transparent wrapper for el-popover component like so.
<script id="my-popover" type="x-template">
<el-popover
ref="mypopover"
transition="el-zoom-in-top"
v-bind="$attrs"
v-on="$listeners"
>
<!-- Pass on all named slots -->
<slot
v-for="slot in Object.keys($slots)"
:slot="slot"
:name="slot"
/>
<span> My popover </span>
</el-popover>
</script>
It works ok with slot="reference" named slot.
<my-popover
placement="bottom"
title="Title"
width="200"
trigger="manual"
v-model="visible"
>
<el-button
slot="reference"
#click="visible = !visible"
>
Click me
</el-button>
</my-popover>
But due to complex layout I need to use v-popover directive. Got no luck with wrapped component.
<my-popover
ref="popover"
placement="right"
title="Title2"
width="200"
trigger="manual"
v-model="visible2"
>
</my-popover>
<el-button
v-popover:popover
#click="visible2 = !visible2"
>
Click me too
</el-button>
So I need somehow to pass in v-popover reference to ref="mypopover" from wrapped component. I.e. pass ref to child directly in template.
I've tried v-popover:popover.$refs.mypopover but that doesn't work.
Related codepen https://codepen.io/anon/pen/rgRNZr
Click on button Click me too should show popup connected to that button.
The problem is that the ref you want is the one that is on the el-popover but you are using the ref that is set on the my-popover component instead of the one you want.
This is kind of a wierd thing since that component wants a ref but it will be annoying to get one from the component inside your component.
I would put the button and popup with a slot in the same component.

Include component from parent app in component contained in node_modules directory

I am working on Vue app that incorporates Vue Bootstrap Calendar, and I would like to be able to override the content of the day cell (handled by the Day.vue component) to add my own custom content inside. My thought was initially to modify the Day component to include <slot></slot> tags and pass in the custom content that way.
The problem has to do with accessing the Day component. To include the calendar in your app, you include the Calendar.vue component, which includes Week.vue, which in turn includes Day.vue. As I understand slots, I have to have the child component (Day.vue in this case) included in the component where I'm passing the data, which means it would need to be included in my own component.
If this is not possible, my other thought is to perhaps modify the library by adding another configuration prop (something like dayCustomContent) to the Calendar.vue that indicates that the Day cell content is custom content, pass that in to Calendar.vue, and then down to Day.vue, and then in the Day.vue template, have a v-if conditional based on this prop that either displays the custom content or the default cell content, something like:
<template>
<div class="day-cell" v-if="dayCustomContent">
...my custom content here...
</div>
<div class="day-cell" v-else>
...default events from my.events goes here...
</div>
</template>
I would probably then need to define a custom component to render whatever custom content I want to display, and somehow include that component within Day.vue.
So to sum up, my questions are these:
1) Is there a way to do what I need with slots?
2) For my second option, am I going down the right path? I'm open to suggestions.
UPDATE: I was able to get this done by adding a boolean customDayContent prop in Calendar.vue like so and passing it down to Week.vue and then to Day.vue:
<template>
...
<div class="dates" ref="dates">
<Week
v-for="(week, index) in Weeks"
:firstDay="firstDay"
:key="week + index"
:week="week"
:canAddEvent="canAddEvent"
:canDeleteEvent="canDeleteEvent"
:customDayContent="customDayContent"
:displayWeekNumber="displayWeekNumber"
#eventAdded="eventAdded"
#eventDeleted="eventDeleted"
></Week>
</div>
...
</template>
<script>
export default {
...
props: {
...
customDayContent: {
type: Boolean,
default: false
}
},
}
</script>
and then in Day.vue, do like I had suggested with v-if:
<template>
<div class="day-cell" v-if="customDayContent">
<custom-day></custom-day>
</div>
<div
class="day-cell"
:class="{'today' : day.isToday, 'current-month' : day.isCurrentMonth, 'weekend': day.isWeekEnd, 'selected-day':isDaySelected}"
#click="showDayOptions"
v-else
>
... existing code goes here...
</div>
</template>
The last part is referencing the CustomDay.vue component referenced in my v-if block. I want the user to be able to define the content of their own custom CustomDay.vue template in their own parent app. However, I'm having trouble trying to figure out how to do that. Following the pattern of including components already in this component, I added this in the components section of Day.vue:
CustomDay: require("../../../../src/Components/CustomDay.vue").default
? require("../../../../src/Components/CustomDay.vue").default
: require("../../../../src/Components/CustomDay.vue")
However, no matter what I try along these lines, I get an error that the relative module was not found. On top of that, I need to add it to the componentsarray only if customDayContent is true. What is the best way to do that? In a watcher or computer property, perhaps? Or another way?

Wrapping content children in a dynamic parent tag with Angular 2

What I want to do
I want to create a reusable Angular 2 button component that may render as an <a /> tag or an <input /> tag depending on an input to the component called type. I want the button component to accept content children which will be rendered as the button label.
To illustrate: an Angular template that invokes my button component like so:<button>Hello</button> should render as <a>Hello</a> in the DOM. However, if a property type="submit" is set (e.g. <button type="submit>Hello</button>) then the output in the DOM should be <input type="submit">Hello</input>.
To further clarify, if I were using React I could create [an overly simplified version of] this component with:
const Button = ({ type, children }) =>
type === "submit"
? <input type="submit">{children}</input>
: <a>{children}</a>
Where I'm stuck
Creating an Angular component that displays content children using <ng-content /> was relatively straightforward. However, I'm yet unable to render those children inside a dynamically chosen tag - either <a /> or <input /> depending on the value of the type property.
What I've tried
I initially tried to use <ng-content /> inside an ngIf or ngSwitch directive, only to find out that <ng-content /> can appear at most once in any given template (unless it’s qualified with a selector). However, I want to output all content children so selectors are not helpful.
I keep finding references to DynamicComponentLoader, but that appears to be deprecated.
I've seen the ContentChildren decorator which would allow my button component to access the content children being passed to it, but I'm not sure how to then take those children and inject them into my component template.
I came across NgTemplateOutlet, which seems like it might help me switch between two entirely different templates (one w/ the <a /> tag and one with the <input /> tag). However that's marked as “Experimental” and I’m having trouble understanding the usage.
Any help would be greatly appreciated!!
#Component({
selector: 'adapting-button',
template: `
<a *ngIf="type !== "submit">{{value}}</a>
<input *ngIf="type === "submit" type="submit" [value]="value">
`,
})
export class AdaptingButtonComponent {
#Input() type: any;
#Input() value: any;
}
#Component({
selector: 'app-root',
templateUrl: `
<adapting-button [type]="'submit'" [value]="Hello"></adapting-button>
`,
})
export class AppComponent {
title = 'app works!';
}

Injecting Angular2 Components as a class or attribute rather than a tag

In Angular1 you could directly insert the HTML into the index.html or index.php like this:
<div ng-controller="pricingController">
{{price}} - Total Cost
</div>
In Angular2 you have to use a component which forces you to use a TemplateURL in the component.
I want to do something more similar to Angular 1's format.
Something like this directly in the HTML:
<div ngComponent="pricing-component">
{{price}} - Total Price
</div>
Rather than this:
<pricing-component></pricing-component>
If you want to use an attribute you can use the attribute selector, and a directive. A directive is a component without a template. Or better said, a component is a directive with a template:
<div pricing>
{{price}} - Total Price
</div>
And your Pricing will have this selector in the directive annotation:
#Directive({
selector : '[pricing]'
})
export class PricingDirective {}

Categories

Resources