Adding class by scrolling to certain sections angular - css

In my SPA build in Angular i want to add a class to the navigation every time the user arrives to a certain section. I have been trying the following solution as seen in this stackblitz.
https://stackblitz.com/edit/angular-ivy-gdxcw8?file=src/app/app.component.ts

You need to query the HTML elements in ngOnInit.
Add this:
ngOnInit() {
this.sections = document.querySelectorAll('section');
this.navLi = document.querySelectorAll('nav .container ul li');
}
After changing your code to:
import { Component, HostListener, VERSION } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
name = 'Angular ' + VERSION.major;
sections: NodeListOf<HTMLElement>;
navLi: NodeListOf<HTMLElement>;
ngOnInit() {
this.sections = document.querySelectorAll('section');
this.navLi = document.querySelectorAll('nav .container ul li');
}
#HostListener('window:scroll', ['$event'])
onscroll() {
var current: any = '';
this.sections.forEach((section) => {
const sectionTop = section.offsetTop;
if (scrollY >= sectionTop - 60) {
current = section.getAttribute('id');
}
});
this.navLi.forEach((li) => {
li.classList.remove('active');
if (li.classList.contains(current)) {
li.classList.add('active');
}
});
}
}
I get your desired behaviour.
Read more about ngOnInit at https://angular.io/guide/lifecycle-hooks

Related

How to optimally apply resize on large data in ACE editor?

I am using ace-editor in my angular app as a JSON editor, ace editor has a feature to dynamically resize based on the data.
When I have data within 1.5k lines it works seamlessly post that the chrome browser get hang, noticed that the CPU utilization is also high
Can any help me to identify how can I resolve this issue or any work around?
If it is an styling issue can anyone suggest how to fit the editor?
Resize logic:
ngAfterViewChecked() {
this.codeEditor.setOptions({
maxLines: this.codeEditor.getSession().getScreenLength(),
autoScrollEditorIntoView: true
});
this.codeEditor.resize();
}
editor.ts:
import {
Component, ViewChild, ElementRef, Input, Output, EventEmitter,
OnChanges, SimpleChanges
} from '#angular/core';
import * as ace from 'ace-builds';
import 'ace-builds/src-noconflict/mode-json';
import 'ace-builds/src-noconflict/theme-github';
const THEME = 'ace/theme/github';
const LANG = 'ace/mode/json';
export interface EditorChangeEventArgs {
newValue: any;
}
#Component({
selector: 'app-editor',
templateUrl: './editor.component.html',
styleUrls: ['./editor.component.css']
})
export class EditorComponent implements OnChanges {
#ViewChild('codeEditor') codeEditorElmRef: ElementRef;
private codeEditor: ace.Ace.Editor;
#Input() jsonObject;
#Input() readMode;
#Output() change = new EventEmitter();
data: any;
mode: any;
constructor() { }
ngOnChanges(changes: SimpleChanges) {
for (const properties of Object.keys(changes)) {
if (properties == 'jsonObject') {
const currentJSONObject = changes[properties];
if (currentJSONObject.currentValue && currentJSONObject.firstChange == false)
this.codeEditor.setValue(JSON.stringify(currentJSONObject.currentValue, null, '\t'), -1);
else if (currentJSONObject.currentValue == null && currentJSONObject.firstChange == false)
this.codeEditor.setValue("");
else
this.data = currentJSONObject.currentValue
}
if (properties == 'readMode') {
const currentReadMode = changes[properties];
if (currentReadMode.firstChange == false)
this.codeEditor.setReadOnly(currentReadMode.currentValue);
else
this.mode = currentReadMode.currentValue
}
}
}
ngAfterViewInit() {
const element = this.codeEditorElmRef.nativeElement;
const editorOptions: Partial<ace.Ace.EditorOptions> = {
highlightActiveLine: true,
displayIndentGuides: true,
highlightSelectedWord: true,
};
this.codeEditor = ace.edit(element, editorOptions);
this.codeEditor.setTheme(THEME);
this.codeEditor.getSession().setMode(LANG);
this.codeEditor.setShowFoldWidgets(true);
this.codeEditor.setHighlightActiveLine(true);
this.codeEditor.setShowPrintMargin(false);
if (this.data)
this.codeEditor.setValue(JSON.stringify(this.data, null, '\t'), -1);
this.codeEditor.setReadOnly(this.readMode);
if (this.mode)
this.codeEditor.setReadOnly(this.mode);
}
ngAfterViewChecked() {
this.codeEditor.setOptions({
maxLines: this.codeEditor.getSession().getScreenLength(),
autoScrollEditorIntoView: true
});
this.codeEditor.resize();
}
onChange(updatedJSON) {
this.change.emit({ newValue: updatedJSON });
}
}
editor.html:
<div ace-editor #codeEditor [autoUpdateContent]="true" [durationBeforeCallback]="1000" (textChanged)="onChange($event)"
(change)="onChange(codeEditor.value)" class="editor">
</div>
Editor CSS property:
.editor {
min-height: 750px;
width: 100%;
}
Using editor component across the application by simply adding following tag in HTML body
<app-editor [jsonObject]="data" [readMode]="readMode" (change)="onChange($event)"></app-editor>

Give class to dynamically created button in angular

I am creating a button and assigning class in component.ts. Style of css does not apply on the button (button font color doest not change). Code of component.ts is
let button = document.createElement('button');
button.innerHTML = 'North';
button.setAttribute('class', 'btn');
let element = document.createElement('div');
element.appendChild(button);
and component.css is
.btn
{
color: red;
}
please try this
button.classList.add("btn");
Use angular components for create buttons
#Component({
selector: 'my-app',
templateUrl: '',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
#ViewChild('element', { read: ViewContainerRef }) container: ViewContainerRef;
constructor(
private _componentFactoryResolver: ComponentFactoryResolver,
private _injector: Injector,
) {}
addButton(): void {
const [componentRef, componentInstance] = this._createButton();
componentInstance.title = 'North'
componentInstance.class = 'active'
this.container.insert(componentRef.hostView);
}
private _createButton(): [ComponentRef<ButtonComponent>, ButtonComponent] {
const componentFactory = this._componentFactoryResolver.resolveComponentFactory(ButtonComponent);
const componentRef = componentFactory.create(this._injector)
const componentInstance = componentRef.instance;
return [componentRef ,componentInstance];
}
}
button component
#Component({
selector: 'app-button',
templateUrl: './button.component.html',
styleUrls: ['./button.component.css'],
})
export class ButtonComponent {
#Input() title: string;
#Input() class: string = '';
}
I put the whole example on stackblitz

Full Calendar's body is not displayed on load

I am trying to display full-calendar module in ngx bootstrap tab teg but at the beginning I am getting only header after clicking header buttons it is displaying all calendar
I have tried to move assignment in ngOnInit but it didn't work
import {AfterViewInit, Component, OnInit} from '#angular/core';
import dayGridPlugin from "#fullcalendar/daygrid";
#Component({
selector: 'app-calendar-module',
templateUrl: './calendar-module.component.html',
styleUrls: ['./calendar-module.component.scss']
})
export class CalendarModuleComponent implements OnInit, AfterViewInit {
public calendarPlugins = [dayGridPlugin];
constructor() { }
ngOnInit() {
}
ngAfterViewInit(){
}
}
<full-calendar
defaultView="dayGridMonth"
[plugins]="calendarPlugins"
[weekends]="false"
[events]="[
{ title: 'event 1', start:'2019-08-19', end:'2019-08-30', color:'red' }
]"
></full-calendar>
Link to screenshot
this worked
ngOnInit() {
setTimeout(() => {
this.calendarComponent.getApi().render();
}, 300);
}

Assign css class in the injected html in Angular 7

I want to assign css class based on some calculation. This is my component class:
#Component({
selector: 'app-render-json',
template: `<div [innerHtml]="html | safeHtml"></div>`,
styleUrls: ['./render-json.component.css'] , encapsulation: ViewEncapsulation.ShadowDom
})
export class RenderJsonComponent {
#Input() myJson: any;
html = ``;
static levelDeep = 1
ngOnInit() {
this.renderJson(this.myJson)
}
renderJson(obj) {
RenderJsonComponent.levelDeep = RenderJsonComponent.levelDeep + 1
for(var key in obj) {
if(key != 'id') {
this.html = this.html + `<div class="col-md-${RenderJsonComponent.levelDeep} col-md-offset-${RenderJsonComponent.levelDeep}">${obj[key]}</div>`
// This does not work but I want to do something like this
}
}
}
}
Basically, I need to render some JSON in a GRID style through bootstrap using offset classes but this does not work somehow. Any help is appreciated.
#Component({
selector: 'app-render-json',
template: `<div [innerHtml]="safeHtml"></div><div *ngFor="jsonElements as element" class="element.class">element.obj</div>`,
styleUrls: ['./render-json.component.css'] , encapsulation: ViewEncapsulation.ShadowDom
})
export class RenderJsonComponent {
#Input() myJson: any;
myLevelDeep = 1;
jsonElements = [];
ngOnInit() {
this.renderJson(this.myJson)
}
renderJson(obj) {
this.myLevelDeep = RenderJsonComponent.levelDeep + 1
for(var key in obj) {
if(key != 'id') {
jsonElements.push({class:"col-md-" + this.myLevelDeep + " col-md-offset-" + this.myLevelDeep, obj: obj[key]});
}
}
}
}

How to pass CSS styles to my Angular 2 component?

I've built an Angular2/4 component that is, basically, a masked date input. I use it in place of a textbox input, and have some code behind it to treat date conversions. It works well enough, but now i want to apply a CSS style and have it changing the input.
I want to write <app-date-input class='someCssClass'></app-date-input> and that class be attributed to my internal input.
My code for the component follows:
date-input.component.html
import { Component, Input, forwardRef } from '#angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '#angular/forms';
import { DatePipe } from "#angular/common";
import * as moment from 'moment';
date-input.component.ts
import { AppConstantsService } from "../../_services";
#Component({
selector: 'app-date-input',
templateUrl: './date-input.component.html',
styleUrls: ['./date-input.component.css'],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DateInputComponent),
multi: true
}]
})
export class DateInputComponent implements ControlValueAccessor {
#Input()
public valor: Date;
#Input()
public readonly: boolean;
public dataString: string;
constructor(public appConstants: AppConstantsService) {
}
atribuirData(dataEntrada: string) {
if (!dataEntrada || dataEntrada == '') {
this.valor = null;
this.propagateChange(this.valor);
return;
}
let parts = dataEntrada.split('/');
try {
let newDate = moment(parts[2] + '-' + parts[1] + '-' + parts[0]).toDate();
// let newDate = new Date(+parts[2], +parts[1]-1, +parts[0]);
this.valor = newDate;
this.propagateChange(this.valor);
} catch (error) {
// return dataEntrada;
console.log(error);
}
}
writeValue(value: any) {
this.valor = value;
const datePipe = new DatePipe('pt-BR');
this.dataString = datePipe.transform(this.valor, 'dd/MM/yyyy');
}
propagateChange = (_: any) => { };
registerOnChange(fn) {
this.propagateChange = fn;
}
registerOnTouched() {
}
}
Although there are multiple ways to achieve this
Setting styles in the Child Component
<app-date-input [childClass]='someCssClass'></app-date-input>
Now in DateInputComponent, create an #Input() property and in the HTML for the component, you can do something like
'<input [class]="input Variable Name">'

Resources