I have a boolean column in my grid which is currently displaying 'true' or 'false' but I want it to show a checkbox instead.
How should I do this.
We are using ag-grid 25 with Angular and Adaptable.
You can write your own cell renderer that renders a checkbox instead of a string. Below is an example:
import { Component, OnDestroy } from '#angular/core';
import { ICellRendererAngularComp } from '#ag-grid-community/angular';
#Component({
selector: 'checkbox-renderer',
template: `
<input
type="checkbox"
(click)="checkedHandler($event)"
[checked]="params.value"
/>
`,
})
export class CheckboxRenderer implements ICellRendererAngularComp, OnDestroy {
private params: any;
agInit(params: any): void {
this.params = params;
}
checkedHandler(event) {
let checked = event.target.checked;
let colId = this.params.column.colId;
this.params.node.setDataValue(colId, checked);
}
}
import { CheckboxRenderer } from "./checkbox-renderer.component";
this.frameworkComponents = {
checkboxRenderer: CheckboxRenderer
};
Live Demo
Resource
https://blog.ag-grid.com/binding-boolean-values-to-checkboxes-in-ag-grid
As you say that you are using AdapTable then you can just add the name of the column to the CheckBoxColumns list in PredefinedConfig / UserInterface
See: https://docs.adaptabletools.com/docs/predefined-config/user-interface-config#checkboxcolumns
So something like:
export default {
UserInterface: {
CheckboxColumns: ['myBooleanColumn'],
},
} as PredefinedConfig;
That will dynamically create a CellRenderer very similar to the one which NearHuscarl suggests.
If the column is ReadOnly the checkboxes will be disabled.
Its worth noting that the CheckboxColumnClickedEvent will fire each time a cell in the column is clicked.
Related
I am trying to add a CSS class to a component immediately after I create it using ViewContainerRef and ComponentFactoryResolver. I want to be able to set the class based on what other Components have already been added to myViewContainerRef.
export class ContainerComponent {
#ViewChild('myContainerRef') myContainerRef: ViewContainerRef
constructor(private factoryResolver: ComponentFactoryResolver,
private renderer: Renderer2) {}
addComponent() {
const componentFactory = this.factoryResolver.resolveComponentFactory(SomeBaseComponent)
const newComponent = this.myContainerRef.createComponent(componentFactory)
// SomeBaseComponent has been added successfully to myContainerRef
// Want to add CSS class to the newComponent
// None of the following statements are adding any styles
if( someLogic()) {
this.renderer.addClass(newComponent.location.nativeElement, 'my-css-class')
this.renderer.addClass(newComponent.el.nativeElement, 'my-css-class')
this.renderer.setStyle(newComponent.el.nativeElement, 'background', 'yellow')
}
}
}
export class SomeBaseComponent {
constructor(public el: ElementRef) {}
}
Is there a better way to go about trying to add the style programmatically? Is there something else I can inject into SomeBaseComponent to be able to add the styles I want at this point, or should I set flags on the newComponent.instance and have the base component be in control of what styles to set on itself?
You should add another #ViewChild which will have a read of ElementRef type.
#ViewChild("myContainerRef", {read: ElementRef}) elementRef: ElementRef;
To set the class attribute, you should use the following.
this.elementRef.nativeElement.setAttribute("class", "test")
Note: I will advised putting the creation logic inside an ngOnInit() method, inside of a custom addComponent().
I have a component that uses #HostBinding to set a class:
#HostBinding('class.dark-1') true;
Which works fine. However, now I need to create a function in my component to change the class dynamically.
For example, from dark-1 to light-2 when a button in the component is clicked.
I know how to create the function and call it from a button, but how do I change the class in the hostbinding and refresh the UI with the new class?
You can toggle a clicked flag when clicking the button, and set the classes with getters:
#HostBinding("class.dark-1") public get classDark1() {
return !this.clicked;
}
#HostBinding("class.light-2") public get classLight2() {
return this.clicked;
}
private clicked = false;
public onClick() {
this.clicked = true;
}
Sinply give it a property name:
#HostBinding('class.dark-1') isDark = true;
Then you can change it:
this.isDark = false;
Or change entire className:
#HostBinding('class') className = 'dark-1';
this.className = 'light-1';
I have got my themes all working perfectly, but for some reason my mat-menu will only get themed on whatever default is called and not otherwise.
So for its theme to not be broken I have to call
#include angular-material-theme($dark-theme);
right at the top of my styles.scss and then have my custom classes that I set, which my light is loaded by default as shown here:
import {OverlayContainer} from "#angular/cdk/overlay";
#Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.scss']
})
export class NavbarComponent implements OnInit, AfterViewInit {
title:string = "Callum.Tech";
themeClass: string = "light-theme";
overlay;
constructor(
private overlayContainer: OverlayContainer
) {
this.overlay = overlayContainer;
}
setDarkTheme(): void {
this.themeClass = "dark-theme";
}
setLightTheme(): void {
this.themeClass = "light-theme";
}
ngOnInit() {
this.overlay.themeClass = this.themeClass;
}
}
Everything else will re-theme and work fine without calling the start include I mentioned but mat-menu will throw a fit and only use the first theme its fed on the site launching, and doesnt change with the rest of the theme.
Here is what it looks like with the dark theme called at the start of styles.scss and the light theme loaded like normal
And here is the dark theme chosen, but the dark theme not called at the start of styles.scss:
In the breaking changes for 2.0.0-beta.11:
overlay: Now that the Overlay is part of the cdk rather than Angular Material directly, the themeClass property has been removed. To add a class to the overlay for theming, you can do
overlayContainer.getContainerElement().classList.add('my-theme-class');
So, you can change your code as follows:
constructor(
private overlayContainer: OverlayContainer
) {
this.overlay = overlayContainer.getContainerElement();
}
toggleTheme(): void {
if (this.overlay.classList.contains("dark-theme") {
this.overlay.classList.remove("dark-theme");
this.overlay.classList.add("light-theme");
} else if (this.overlay.classList.contains("light-theme") {
this.overlay.classList.remove("light-theme");
this.overlay.classList.add("dark-theme");
} else {
this.overlay.classList.add("light-theme");
}
}
ngOnInit() {
this.toggleTheme();
}
I want to make dropdown keyboard accessible. Right now, its not working when i am using keyboard up and down arrow. I applied tabindex but still not working. Anyone have any idea about this..
<p-dropdown [options]="cities" tabindex="1" placeholder="Select an option"></p-dropdown
I tried this it working properly using keyboard up and down arrow :
npm version :
"primeng": "^4.1.3"
in html file
<p-dropdown [options]="cities" [(ngModel)]="selectedCity" tabindex="1" placeholder="Select an option"></p-dropdown>
module.ts
import { DropdownModule } from 'primeng/primeng';
#NgModule({
imports: [
DropdownModule
]
})
component.ts
import {SelectItem} from 'primeng/primeng';
cities: SelectItem[];
selectedCity: string;
PrimeNG not support reading dropdown options by default. Default behavior is navigation by arrows and change value. Default tabulator key action is hide overlay with element items. My solution forces tabulator key to choose dropdown option and when you hit enter key the value is changed.
I prepared angular directive which override default dropdown behavior. You can add add this directive do module and import it in place where you want use this change.
Testing for PrimeNG 8.0.0:
#Directive({
selector: 'p-dropdown',
})
export class DropdownDirective implements OnInit, OnDestroy {
readonly KEY_DOWN_EVENT: string = 'keydown';
readonly FOCUS_IN_EVENT: string = 'focusin';
readonly TABINDEX_ATTRIBUTE: string = 'tabindex';
readonly LIST_ITEM_SELECTOR: string = 'li';
private focusInSubscription: Subscription = new Subscription();
private subscriptions: Subscription = new Subscription();
private listElementSubscriptions: Subscription[] = [];
private readonly dropdownHtmlElement: HTMLElement;
constructor(private dropdown: Dropdown,
private elementRef: ElementRef) {
this.dropdownHtmlElement = this.elementRef.nativeElement as HTMLElement;
}
ngOnInit(): void {
this.replaceKeyDownAction();
this.subscribeToDropdownShowEvent();
this.subscribeToDropdownHideEvent();
}
ngOnDestroy(): void {
this.subscriptions.unsubscribe();
}
private subscribeToDropdownShowEvent() {
this.subscriptions.add(
this.dropdown.onShow.subscribe(() => {
this.updateElementsList();
this.subscribeToFocusInEvent();
}),
);
}
private subscribeToDropdownHideEvent() {
this.subscriptions.add(
this.dropdown.onHide.subscribe(() => {
this.unsubscribeFromFocusInEvent();
this.unsubscribeFromListElementsKeyDownEvents();
}),
);
}
private updateElementsList() {
const listElements = this.dropdownHtmlElement.querySelectorAll<HTMLLIElement>(this.LIST_ITEM_SELECTOR);
listElements.forEach((listElement: HTMLLIElement) => {
this.subscribeToListElementKeyDownEvent(listElement);
listElement.setAttribute(this.TABINDEX_ATTRIBUTE, '0');
});
}
private subscribeToListElementKeyDownEvent(listElement: HTMLLIElement) {
this.listElementSubscriptions.push(
fromEvent(listElement, this.KEY_DOWN_EVENT)
.pipe(filter((event: KeyboardEvent) => event.key === KEYBOARD_KEY.ENTER))
.subscribe(() => {
// Simulation of mouse click of list element (trigger with (click) event in p-dropdownItem component which is child element of p-dropdown)
listElement.click();
}),
);
}
private unsubscribeFromListElementsKeyDownEvents() {
this.listElementSubscriptions.forEach((singleSubscription: Subscription) => singleSubscription.unsubscribe());
this.listElementSubscriptions = [];
}
private subscribeToFocusInEvent() {
this.focusInSubscription = fromEvent(document, this.FOCUS_IN_EVENT).subscribe(({target}) => {
// Situation when focus element is outside dropdown component
if (!this.dropdownHtmlElement.contains(target as HTMLElement)) {
this.dropdown.hide();
}
});
}
private unsubscribeFromFocusInEvent() {
this.focusInSubscription.unsubscribe();
}
/**
* Overwrite default onKeydown method from PrimeNG dropdown component
*/
private replaceKeyDownAction() {
const onKeyDownOriginFn = this.dropdown.onKeydown.bind(this.dropdown);
this.dropdown.onKeydown = (event: KeyboardEvent, search: boolean) => {
if (event.which === 9) {
// Napisuję domyślne zachowanie tabulatora zdefiniowanego w klasie komponentu Dropdown z biblioteki PrimeNG
} else {
onKeyDownOriginFn(event, search);
}
}
}
}
I have the following component class that receives an observable from a service. I want my component to unsubscribe when destroyed. This is the code is working and the view gets updated (the view renders different content depending on the value of state with *ngIf):
#Component({
templateUrl: 'my-widget.component.html',
selector: 'my-widget'
})
export class MyWidgetComponent implements OnInit, OnDestroy {
// Enum type variable to keep state
state: MyWidgetStateType;
// This is needed to be able to use the enum type in the template
private myWidgetStateType = MyWidgetStateType;
// Keep a reference to the observable to unsubscribe from it
private sub: Subscriber<any>;
constructor(public myWidgetService: MyWidgetService) {
}
ngOnInit(): void {
this.sub = Subscriber.create((state: MyWidgetStateType) => {
console.log('Widget state: ' + MyWidgetStateType[state]);
this.state = state;
});
this.myWidgetService.getState().subscribe(this.sub);
}
ngOnDestroy(): void {
// Unsubscribe here
this.sub.unsubscribe();
}
}
The state type is an enum with 3 states:
export enum MyWidgetStateType {
Enabled,
Dormant,
Locked
};
And the view my-widget.component.html:
<h2>My Widget</h2>
<div *ngIf="state === myWidgetStateType.Enabled">
<p>Enabled</p>
</div>
<div *ngIf="state === myWidgetStateType.Dormant">
<p>Dormant</p>
</div>
<div *ngIf="state === myWidgetStateType.Locked">
<p>Locked</p>
</div>
However, if I try to extract the call in the subscriber to a private function, the console.log method works but the view doesn't render any content according to the state (the <h2> title is rendered but there is no <div> element):
#Component({
templateUrl: 'my-widget.component.html',
selector: 'my-widget'
})
export class MyWidgetComponent implements OnInit, OnDestroy {
// Enum type variable to keep state
state: MyWidgetStateType;
// This is needed to be able to use the enum type in the template
private myWidgetStateType = MyWidgetStateType;
// Keep a reference to the observable to unsubscribe from it
private sub: Subscriber<any>;
constructor(public myWidgetService: MyWidgetService) {
}
ngOnInit(): void {
this.sub = Subscriber.create(this.onStateChange);
this.myWidgetService.getState().subscribe(this.sub);
}
ngOnDestroy(): void {
// Unsubscribe here
this.sub.unsubscribe();
}
private onStateChange(state: MyWidgetStateType): void {
console.log('Widget state: ' + MyWidgetStateType[state]);
this.state = state;
}
}
The question is: why if the onStateChange function gets called, the view never gets the value update?
Of course this is not blocking my work because I have the solution above, but I'm just curious.