How to pass CSS styles to my Angular 2 component? - css

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">'

Related

The dom is not reflective of the actual value wen using onPush strategy with ngrx store subscription

component file:
// Angular and 3rd party libs imports
import { ChangeDetectionStrategy, Component, OnInit } from '#angular/core';
import { Store } from '#ngrx/store';
import { UntilDestroy, untilDestroyed } from '#ngneat/until-destroy';
// Utils
import { ApiLoadInfo, ApiStateEnum } from 'src/app/shared/utils/states';
// Services
import { TestPortalService } from '../../../testportal.service';
import { SharedClient } from 'src/app/shared/services/shared.service';
// Redux
import {
CandidateInstructionsState,
Quiz,
Instruction,
PageEnum,
LandingPageData
} from '../redux/candidate-instructions.state';
import * as instructionActions from '../redux/candidate-instructions.action';
import * as instructionSelects from '../redux/candidate-instructions.selector';
import { ActivatedRoute } from '#angular/router';
#UntilDestroy()
#Component({
selector: 'candidate-instructions-landing',
templateUrl: './instructions-landing.component.html',
styleUrls: ['./instructions-landing.component.scss', '../common.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CandidateInstructionsLandingComponent implements OnInit {
// Exposing constants to html template
ApiStateEnum = ApiStateEnum;
PageEnum = PageEnum;
// Variables
initDataLoadState: ApiLoadInfo;
data: LandingPageData;
constructor(private _store: Store<CandidateInstructionsState>,
private _activatedRoute: ActivatedRoute,
private _testPortalService: TestPortalService,
) {
_store
.select(instructionSelects.selectInitDataLoadState)
.pipe(untilDestroyed(this))
.subscribe((initDataLoadState) => {
console.log('is same ref?:', this.initDataLoadState === initDataLoadState)
this.initDataLoadState = initDataLoadState;
console.log(initDataLoadState)
console.log('----------')
});
_store
.select(instructionSelects.selectLandingData)
.pipe(untilDestroyed(this))
.subscribe((data) => {
this.data = data;
});
}
ngOnInit() {
this.loadInstructions();
}
loadInstructions() {
this._store.dispatch(instructionActions.setInitData()); // sets state to 'loading'
this._testPortalService.getTestInstructions(
this._activatedRoute.snapshot.params.quizOrInviteId,
(error, response) => {
if (error) {
// sets state to 'error'
this._store.dispatch(instructionActions.setInitDataFail({ errmsg: error.toString() }));
} else {
// sets state to 'loaded'
this._store.dispatch(instructionActions.setInitDataSuccess({ instructions: response }));
console.log(response);
}
}
);
}
}
html:
{{ initDataLoadState.state }}
console output:
ui:
I thought when onPush is set, the template will re-render if the variable ref is changed. And since redux store is immutable that is always supposed to happen (confirmed by logging in the console). But still the actual component data is not in sync with the UI ie. component value = "loaded" but value in ui = "loading". Why is it so?
If you don't want to or can't use the pushPipe you could do something like this to subscribe to the store data:
import { Component, OnDestroy, OnInit } from '#angular/core';
import { Subscription } from 'rxjs';
import { Store } from '#ngrx/store';
import { getData } from 'path/to/store';
import { YourType } from 'path/to/type';
#Component({
selector: 'subscribing-component',
templateUrl: './subscribing.component.html'
})
export class SubscribingComponent implements OnInit, OnDestroy {
data: YourType;
dataSubscription: Subscription;
constructor(store: Store) {}
ngOnInit(): void {
this.dataSubscription = this.store.select(getData).subscribe((data) => {
this.data = data;
});
}
// don't forget to unsubscribe
ngOnDestroy(): void {
if (this.dataSubscription) {
this.dataSubscription.unsubscribe();
}
}
}

Fetch data from asp.net into highchart

I'm trying to make an application with highchart and asp.net and I followed several tutorials and applications because it's a new thing for me.
But I don't know how to fetch data from asp.net into highcharts.js. I tried to do a getChartData function following one video and then I realised that is for chart.js.Can you give me a idea?
This is my code:
bar-chart.ts
import { Component, OnInit } from '#angular/core';
import * as Highcharts from 'highcharts';
import { SalesDataService } from '../../services/sales-data.service';
import * as moment from 'moment';
#Component({
selector: 'app-bar-chart',
templateUrl: './bar-chart.component.html',
styleUrls: ['./bar-chart.component.css']
})
export class BarChartComponent implements OnInit {
constructor(private _salesDataServices:SalesDataService ){}
orders:any;
orderLabels:string[];
orderData:number[];
public barChartLabels:string[];
public barChartData:any[];
title = 'myHighChartsApp';
highcharts = Highcharts;
public options: any ={
chart : {
type: "column"
},
title: {
text: "Monthly Sales Chart Department Wise"
},
xAxis:{
},
yAxis: {
title:{
text:"Sales in Million $"
}
},
series: []
}
ngOnInit() {
}
getChartData(res:Response){
this.orders=res['page']['data'];
const data=this.orders.map(o =>o.total);
const formattedOrders=this.orders.reduce((r,e) => {
r.push([moment(e.placed).format('YY-MM-DD'),e.total]);
return r;
},[]);
const p=[];
console.log('formattedOrders:',formattedOrders);
const chartData=formattedOrders.reduce((r,e)=>{
const key=e[0];
if(!p[key]){
p[key]=e;
r.push(p[key]);
}else {
p[key][1]+=e[1];
}
return r;
},[]);
return chartData;
}
}
sales-data-service.ts
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
import { Observable } from 'rxjs';
import { Order } from '../shared/order';
#Injectable({
providedIn:'root'
})
export class SalesDataService {
constructor(private _http: Http) { }
getOrders( pageIndex: number, pageSize: number
) {
return this._http.get('http://localhost:5103/api/order/'+ pageIndex + '/' + pageSize
)
.map(res => res.json());
}
}

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>

Angular: How to filter a dataTable using query params

I want to filter my table using query params that I got from the user input in another component.
I am able to get the data that the users send through the input and print it to the console.log. But I don't know how to use it to filter the table.
i have built a filter but for some reason i cant call it.
This is my filter :
import { Pipe, PipeTransform } from "#angular/core";
import { Container } from "./Entites/Container";
#Pipe({
name: 'textFilter'
})
export class textFilter implements PipeTransform {
transform(
containers : Container[],
storageSearch?: any,
clientSearch?: string,
): Container[] {
if (!containers) return [];
if (!storageSearch) return containers;
storageSearch = storageSearch.toLocaleLowerCase();
containers = [...containers.filter(user => user.TAOR_QTSR_EBRI.toLocaleLowerCase() === storageSearch)];
if (!clientSearch) return containers;
clientSearch = clientSearch.toLocaleLowerCase();
containers = [...containers.filter(user => user.LQOCH_SHM_LEOZI_QTSR.toLocaleLowerCase() === clientSearch)];
// if (!roleSearch) return users;
//roleSearch = roleSearch.toLocaleLowerCase();
//users = [...users.filter(user => user.role.toLocaleLowerCase() === roleSearch)];
return containers;
}
}
This is my component ngOnInit i have some other filters there, for example checkbox filter :
ngOnInit() {
this.marinService.getAllContainers().subscribe((result) => {
//Data
this.dataSource = new MatTableDataSource(result);
//Paginator
this.dataSource.paginator = this.paginator;
//AutoFilter Form 1st page
this.clientType = this.route.snapshot.queryParamMap.get('clientType');
this.storageType= this.route.snapshot.queryParamMap.get('storageTypes');
console.log('The Client name is : '+this.clientType+' '+'The storage Facility is : '+this.storageType);
//CheckBox Filter
this.dataSource.filterPredicate = (data: Container, filter: any) => {
return filter.split(',').every((item: any) => data.SOG_MCOLH.indexOf(item) !== -1);
};
this.filterCheckboxes.subscribe((newFilterValue: any[]) => {
this.dataSource.filter = newFilterValue.join(',');
});
});
}
What I want to accomplish is to be able to filter the table using the query params.
We can pass the data which you have received as input (in the parent component) to the material table filtering function applyFilter inside the child component...
relevant parent TS:
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
styles: [`.parent{background:lightgreen; padding:2%;}`],
template: `
Enter string for filtering: <input type='text' [(ngModel)]='inputStr' />
<!-- {{inputStr}} -->
<table-filtering-example [inputStr]='inputStr'>loading</table-filtering-example>
`,
})
export class AppComponent {
inputStr: string = '';
constructor() { }
}
relevant child TS:
export class TableFilteringExample implements OnInit, OnChanges {
displayedColumns: string[] = ['position', 'name', 'weight', 'symbol'];
dataSource = new MatTableDataSource(ELEMENT_DATA);
#Input() inputStr:string;
constructor(){}
ngOnInit(){}
ngOnChanges(){
/* just call the applyFilter button with the data which is passed to your component from it's parent */console.log("(ngOnChanges)this.inputStr:", this.inputStr);
this.applyFilter(this.inputStr);
}
applyFilter(filterValue: string) {
this.dataSource.filter = filterValue.trim().toLowerCase();
}
}
complete working stackblitz here

Return firebase values from a service to a component angular 6

I'm creating an application with angular 6 and firebase using angularfire2, I chose to use the firestore where I have a collection called pages like in the image:
basically I created a service - "PagesService" where I have a function that returns the data of the page that I sent. I'm trying to use getPage to return the values to my component, and assign them to the form, nothing else I tried worked, only returns an "observable" that I can not work, does anyone have an idea of what I can do?
Full code, service:
import { Injectable } from '#angular/core';
import { AngularFirestore, AngularFirestoreCollection, AngularFirestoreDocument } from 'angularfire2/firestore';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
#Injectable()
export class PagesService {
private pagesCollection: AngularFirestoreCollection<any>;
private page: AngularFirestoreDocument<any>;
constructor(private afs: AngularFirestore) {
this.pagesCollection = afs.collection('pages');
}
getPage(pageName: string) {
return this.afs.doc<any>('pages/${pageName}').valueChanges();
}
addPages(pageName: string, pageForm: any) {
this.pagesCollection.doc(pageName).set(pageForm.value);
}
}
My component:
import { Component, OnInit } from '#angular/core';
import { FormBuilder, FormGroup } from '#angular/forms';
import { Observable } from 'rxjs';
import { PagesService } from '../../services/pages.service';
#Component({
selector: 'app-quem-somos',
templateUrl: './quem-somos.component.html',
styleUrls: ['./quem-somos.component.scss']
})
export class QuemSomosComponent implements OnInit {
pageForm: FormGroup;
pageName: string = "wo-we-are";
page: any;
constructor(private pagesService: PagesService, private fb: FormBuilder) { }
ngOnInit() {
this.page = this.pagesService.getPage(this.pageName);
console.log(this.page);
this.pageForm = this.fb.group({
title: '',
content: ''
});
}
save() {
this.pagesService.addPages(this.pageName, this.pageForm);
}
}
obs: Sorry my english
If I have understand you right, When you say "Observable that I cannot work" is mean that you cannot access his data when you are trying to assign its values in the form?
In this case (I assume that your service is working as expected), just subscribe to it and populate the form after your values are ready to use. for example:
ngOnInit() {
this.pagesService.getPage(this.pageName).subscribe(v => {
// Here your data is ready, so you can send it to a function and populate the form as you need.
this.populateForm(v);
});
// Here I just construct the FormGroup, so your application can rendered.
this.pageForm = this.fb.group({
title: '',
content: ''
});
}
And add this function to do the task:
populateForm = (data) => {
console.log(data); // Just log it in console, and see if its the data that you seek for
}
Instead of console.log() you can populate your form or do what ever you need to.
Good Luck !
--EDIT--
I just noticed now, In your service:
getPage(pageName: string) {
return this.afs.doc<any>('pages/${pageName}').valueChanges();
}
You call the doc with ' ' instead of ``, so In fact, you are not using Template Strings. So your call is wrong and not fetch with the right path.
Change it to:
return this.afs.doc<any>(`pages/${pageName}`).valueChanges();

Resources