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]});
}
}
}
}
Related
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
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>
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
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">'
I have an angular2 app with an RC5 style submodule. The module is my tutorial module, with tutorial.component as it's root component.
#Component({
selector: 'tutorial',
template: `
<div class="content row">
<div class="col s9">
<h1>Tutorial</h1>
<router-outlet></router-outlet>
</div>
</div>`,
styleUrls: ['./app/tutorial/tutorial.css'],
directives: [ROUTER_DIRECTIVES],
encapsulation: ViewEncapsulation.None
})
export class tutorialComponent {
public chapters = _chapters;
clickedItem: number = 0;
}
Here you can see the module routes:
const tutorialRoutes: Routes = [
{
path: 'tutorial',
component: tutorialComponent,
children: [
{ path: 'chapter/:id', component: chapterComponent },
{ path: '', redirectTo: 'chapter/0', pathMatch: 'full'},
]
}
];
So that's fine, however, in my child Component, chapterComponent, my css isn't being applied. Here is the component:
#Component({
selector: 'chapter',
template: `<div [innerHTML]="content"></div>`,
styleUrls: ['./app/tutorial/chapter/chapter.css']
})
export class chapterComponent implements OnInit, OnDestroy {
private sub: Subscription;
private content: string = '';
constructor( private route: ActivatedRoute) { }
ngOnInit() {
this.sub = this.route.params.subscribe(params => {
var id: string = params['id'];
this.content = id;
var that = this;
var _url = './chapter/' + params['id'] + '.html';
$.ajax({
url: _url,
success: function (result) {
that.content = result;
}
});
});
}
}
But if I use the exact same path to the chapter.css file in my tutorial component, then the styles are applied.
Why are my child components behaving differently to parent components with respect to css application.