How to format date in Angular Kendo Grid - kendo-grid

I working on Angular Kendo Grid and I am getting server data in format
1900-01-01T00:00:00
But I want it to display in standard format, not sure how to do it. I have applied format='{0:MM/dd/yyyy h:mm a}' in grid column but no effect. What ever data format conversion to do, I need to do at client side of code i.e server date to javascript format!!
<kendo-grid-column field="mydata.openDate" width="220" title="Open Date" filter="date"
format='{0:MM/dd/yyyy h:mm a}'>
</kendo-grid-column>

Try this:
<kendo-grid-column field="dateField" width="220" title="Open Date">
<ng-template kendoGridCellTemplate let-dataItem>
{{dataItem.dateField | date: 'MM/dd/yyyy'}}
</ng-template>
</kendo-grid-column>
You can also use short or other formats provided by angular Date Pipe

if you have a big project and you have to use the same format multiple times then a directive is the way to go.
This is super important for the usability and in case you decided to change the format you use (Maintenance)
import { Directive, OnInit } from '#angular/core';
import { ColumnComponent } from '#progress/kendo-angular-grid';
#Directive({
selector: '[kendo-grid-column-date-format]'
})
export class KendoGridColumnDateFormatDirective implements OnInit {
constructor(private element: ColumnComponent) {
}
ngOnInit() {
this.element.format = "{0:dd.MM.yyyy}";
}
}
and you can use it like this
<kendo-grid-column field="yourField"
title="your title"
kendo-grid-column-date-format>
</kendo-grid-column>
Super important do not forget to register the directive

The Grid data needs to contain actual JavaScript Date objects as opposed to some string representations. Then built-in formatting, sorting, filtering and editing will treat the dates as such and will work as expected:
Docs
Map the data so that it contains actual dates.
EXAMPLES:
String
Date

Related

How to Extract just the Date from Angular Material Datepicker

I have a reactive form and inside it I want to use the angular material datepicker. I've extracted the value from the datepicker using (dateChange) but the value it self is of the type object and included much more than what I need. Sun Aug 11 2019 00:00:00 GMT-0400 (Eastern Daylight Time)
Is there away to get just the Month, Day, and the Year Aug 11 2019 without all the rest?
HTML
<mat-form-field>
<input matInput [matDatepicker]="dp" placeholder="Choose a date (dateChange)="updateDOB($event)" disabled>
<mat-datepicker-toggle matSuffix [for]="dp"></mat-datepicker-toggle>
<mat-datepicker touchUi #dp disabled="false"></mat-datepicker>
</mat-form-field>
TS (pretty simple at the moment)
updateDOB(dateObject) {
console.log(dateObject.value);
}
I've been reading a bunch of documentation but still can't figure it out. Any help is greatly appreciated.
-Update-
I was able to come up with a work around for the problem. I stringified the object value and then trimmed the string to just included the date.
updateDOB(dateObject) {
// convert object to string then trim it to yyyy-mm-dd
const stringified = JSON.stringify(dateObject.value);
const dob = stringified.substring(1, 11);
this.applicant.contact[0].dob = dob;
}
The result now comes out to 2019-08-11 which works for me.
If anyone has any other suggestions I'd still be happy to hear them.
Try this,
updateDoB(dateObject){
console.log("DATE in dd/mm/yyyy",dateObject.toLocaleDateString())
}
another way to do it:
dateObject.value.toLocaleString().substring(1, 10)
I had a very similar problem. I solved it using MomentDateAdapter and custom directive. Steps i took:
install #angular/material-moment-adapter and moment.js
add date format configuration :
export const DATE_FORMATS = {
parse: {
dateInput: ['MMM DD yyyy']
},
display: {
dateInput: 'MMM DD yyyy',
monthYearLabel: 'MMM yyyy',
dateA11yLabel: 'LL',
monthYearA11yLabel: 'MMMM yyyy',
},
};
First 'dateInput' matters how You should enter date (using keyboard for example) to be successfully parsed. Second 'dateInput' matters what format is used to dipslay date.
Define providers:
{ provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE, MAT_MOMENT_DATE_ADAPTER_OPTIONS]},
{ provide: MAT_DATE_FORMATS, useValue: DATE_FORMATS }
Create custom directive:
import {
Directive,
EventEmitter,
HostListener,
Input,
Output,
} from '#angular/core';
#Directive({
selector: '[setOutputDateFormat]',
})
export class DateFormatDirective {
#Input('setOutputDateFormat')
inputFormat = null;
#Output()
dateChangeWithFormat = new EventEmitter<string>();
constructor() {}
#HostListener('dateChange', ['$event'])
onDateChange(event: any) {
const dateFormatted = event.value.format(this.inputFormat);
this.dateChangeWithFormat.emit(dateFormatted);
}
}
Directive listens to 'dateChange' events, event.value attribute should contain date in moment object (as we switched to MomentDateAdapter at the beginning), so directive switches format to the desired ones and fires custom event with the desired format
Lastly use the directive inside template providing custom format in 'outputDateFormat' property:
<mat-form-field>
<input
matInput
[setOutputDateFormat]="outputDateFormat"
[matDatepicker]="dp"
placeholder="Choose a date"
(dateChangeWithFormat)="updateDOB($event)"
/>
<mat-datepicker-toggle matSuffix [for]="dp"></mat-datepicker-toggle>
<mat-datepicker touchUi #dp disabled="false"></mat-datepicker>
</mat-form-field>
Example here: https://stackblitz.com/edit/angular-ivy-beufcw?file=src/app/app.component.ts
Now it seems that moment.js project has a legacy status, so better solution would be switch to luxon date adapter (it shouldn't be hard because luxon is moment.js successor)

Two way data binding without ngmodel directive angular

I see in console ngmodel is deprecated and will be removed on angular 7. and i have a directive using it for do a two way databinding, how i can do it wihout [(ngmodel)]?
import {Directive, ElementRef, HostListener} from '#angular/core';
#Directive({
selector: '[onlyFloat]'
})
export class OnlyFloatDirective {
private regex: RegExp = new RegExp(/^-?[0-9]+(\.[0-9]*){0,1}$/g);
private specialKeys: Array<string> = [ 'Backspace', 'Tab', 'End', 'Home', '-' ];
constructor(private el: ElementRef) {
}
#HostListener('keydown', [ '$event' ])
onKeyDown(event: KeyboardEvent) {
if (this.specialKeys.indexOf(event.key) !== -1) {
return;
}
let current: string = this.el.nativeElement.value;
let next: string = current.concat(event.key);
if (next && !String(next).match(this.regex)) {
event.preventDefault();
}
}
}
HTML:
<div class="ui-g-12 ui-md-6">
<label >Valor da Venda</label><br>
<input type="text" pInputText onlyFloat [(ngModel)]="produtoAgilForm.controls['ValorVenda'].value" placeholder="Valor Venda" formControlName="ValorVenda">
</div>
Just for clarity, note that ngModel is only deprecated when used with Reactive forms. That has been the recommendation for a while ... but now it is deprecated in v6 and will be removed in v7.
See this part of the docs for more information: https://angular.io/api/forms/FormControlName
And in case that part of the docs is removed when ngModel is removed:
Support for using the ngModel input property and ngModelChange event
with reactive form directives has been deprecated in Angular v6 and
will be removed in Angular v7.
Now deprecated:
<form [formGroup]="form"> <input
formControlName="first" [(ngModel)]="value"> </form>
this.value = 'some value';
This has been deprecated for a few reasons.
First, developers have found this pattern confusing. It seems like the
actual ngModel directive is being used, but in fact it's an
input/output property named ngModel on the reactive form directive
that simply approximates (some of) its behavior. Specifically, it
allows getting/setting the value and intercepting value events.
However, some of ngModel's other features - like delaying updates
withngModelOptions or exporting the directive - simply don't work,
which has understandably caused some confusion.
Here is the recommended change per the above referenced docs:
To update your code before v7, you'll want to decide whether to stick
with reactive form directives (and get/set values using reactive forms
patterns) or switch over to template-driven directives.
After (choice 1 - use reactive forms):
<form [formGroup]="form">
<input formControlName="first">
</form>
this.form.get('first').setValue('some value');
And to answer your question ... you shouldn't need ngModel here. Your binding should be handled by your use of the formControlName. And to set the value, use the above shown code.
Is your directive not working? If not, could you provide a stackblitz to demonstrate?

Working with custom components for input generates "No value accessor for form control with path X->0->Y"

I have a working form taking the following HTML markup. No errors or warnings.
<div class="input-element">
<div class="input-caption">Title</div>
<input type="text"
formControlName="targetField"
class="form-control">
</div>
I transformed it into a custom component, which also works, as shown below.
<app-input-text [info]="'Title'"
formControlName="targetField"
ngDefaultControl></app-input-text>
In my next view, I need to use FormArray as follows - still working code.
<div formArrayName="stuff">
<div *ngFor="let thing of form.controls.stuff.controls; let i = index;"
[formGroupName]=i>
<div class="input-element">
<div class="input-caption">Title</div>
<input type="text"
formControlName="targetField"
class="form-control">
</div>
</div>
</div>
Now, I expected that combining both (i.e. being able to use custom input component and being able to form array for components) would post no problem. However, the sample below doesn't work.
<div formArrayName="stuff">
<div *ngFor="let thing of form.controls.stuff.controls; let i = index;"
[formGroupName]=i>
<app-input-text [info]="'Title'"
formControlName="targetField"
class="col-sm-6"></app-input-text>
</div>
</div>
It generates the following error.
No value accessor for form control with path: 'stuff -> 0 -> targetField'
The custom component is design like this (although given that it works in the explicit markup example, I'm not sure if it's relevant information). The only (wild) guess I have might be that value isn't jacked into the form array field somehow.
export class InputTextComponent implements OnInit {
constructor() { this.value = new EventEmitter<string>(); }
#Input() info: string;
#Output() value: EventEmitter<string>;
onEdit(value: any): void { this.value.emit(value); }
}
The group and array creating in the current view is done like this (not sure if this is of any relevance neither, as it works for the explicit HTML markup case).
this.form = builder.group({
id: "",
stuff: builder.array([
builder.group({ targetField: "aaa" }),
builder.group({ targetField: "bbbb" }),
builder.group({ targetField: "cc" })
])
});
Is there a limitation in Angular in this regard that I'm not aware of? I'm rather sure there's not and that I'm just doing something fairly clever simply missing a tiny detail.
I do understand the error but I can't see how it relates to the code. The form can't find the 0th element in the array or that element has no field of that name. Since I do get to see a few rows, I know there must be a 0th element. Since I specified the name of the field, I know there is indeed such. What else am I missing?

Angular 4 shows time part wrong in datetime

I have an input on my Angular component html like this:
<input id="orderdate" class="form-control" value="{{order.OrderDate | date: 'd.M.yyyy H:mm:ss'}}" disabled />
order.OrderDate has value 2017-06-01T10:52:03.666723, and I expect to see value in format
1.6.2017 10:52:03.
However, what I actually get is
1.6.2017 10:00:6/1/2017 10:52:03 AM:6/1/2017 10:52:03 AM
If I use only date (d.M.yyyy), it works correctly (1.6.2017). Why is the time part showing wrong?
I think its supposed to be in this format 'd.M.y H:mm:ss'.
Angular Date Pipe
Thanks to comment by Thiagz, I found solution to this problem here: Angular2 date pipe does not work in IE 11 and edge 13/14.
This seems to be bug in IE and Edge, so I had to create my own pipe for date.
DatexPipe.ts:
import { Pipe, PipeTransform } from '#angular/core';
import * as moment from 'moment';
#Pipe({
name: 'datex'
})
export class DatexPipe implements PipeTransform {
transform(value: any, format: string = ""): string {
var momentDate = moment(value);
if (!momentDate.isValid()) return value;
return momentDate.format(format);
}
}
Use it like this:
<input id="orderdate" class="form-control" value="{{order.OrderDate | datex: 'd.M.YYYY H:mm:ss'}}" disabled />

Styled HTML content dynamically switched with tabs using Angular 2

I am attempting to create a reusable angular2 component that accepts an array of URLs to html files on my server and creates a content window with tabs to switch between "chapters", effectively swapping out the html and css inside the content window. I have tried all sorts of things including iframes but those don't work, the angular 1 ng-include work-arounds that I can find on StackOverflow but they have all since been deprecated, and the closest I've got is building a component that you can #Input html and it interpolates the content but style won't apply and angular strips out any style or script tags. Here is what I have tried.
In my parent component class:
htmlInput: string = "<h1>Why Does Angular make this so hard?</h1>";
cssInput: string = "h1 { color:red; }"
Parent Component HTML:
<app-html [html]='htmlInput' [css]='cssInput'></app-html>
My HTML Component:
import { Component, Input, OnInit } from '#angular/core';
#Component({
selector: 'app-html',
template: '<div [innerHtml]=html></div>', //This works but no style
//template: '{{html}}', //This displays the actual markup on page
styles: ['{{css}}'] //This does nothing
//styles: ['h1 { color: red; }']//Also nothing
})
export class HtmlComponent implements OnInit {
#Input() html: string = "";
#Input() css: string = "";
ngOnInit() {
}
}
The result of this code is
Why Does Angular make this so hard?
But no red color. Maybe style is applied before the innerHtml is added to DOM? I don't know but just putting {{html}} results in displaying the actual markup with the h1 tags visible.
The reason I want to do it this way is that I have a bunch of HTML pages already created sitting in a folder on my server from before I angularized my site that all share a single style sheet. I'd like to just be able to flip through them like pages in a book without reloading the page and since there are so many and I'm likely to add more all the time, I'd really rather not create routing for every single one. (I already have routing for basic site navigation.)
Does anybody have a better suggestion for how to embed styled HTML into a page dynamically in the most recent version of Angular 2? At the time of this post we are in 2.0.0-beta.17.
OR... I already figured I may be approaching this issue from the entirely wrong angle. There must be a reason Angular is making this so difficult and deprecating all the solutions people have come up with so If anyone has a suggestion about how I could achieve the same results in a more angular friendly way I'd love to hear that too.
Thank you.
Edit:
I was able to fix my issue by creating a pipe which sanatizes the html before adding it to an iframe.
import { Pipe, PipeTransform } from '#angular/core';
import { DomSanitizer } from '#angular/platform-browser';
#Pipe({ name: 'safe' })
export class SafePipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {}
transform(url: string) {
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
}
}
And then you can just pass your html into the iframe.
<iframe width="100%" height="1000" frameBorder="0" [src]="url | safe"></iframe>
This is useful to me since I have some old pages that use all sorts of jquery and style etc. This works as a quick fix to have them show up.
Angular2 rewrites the styles added to a component by including the dynamically added attributes like _ngcontent-yle-18 into the CSS selectors.
Angular2 uses this to emulate shadow DOM style encapsulation. These attributes are not added to dynamically added HTML (for example with innerHTML).
Workarounds
add styles to index.html because these styles are not rewritten by Angular2
set ViewEncapsulation.None because then Angular doesn't add the encapsulation emulation attributes
use /deep/ to make Angular2 ignore the encapsulation emulation attributes
See also Angular 2 - innerHTML styling
You should wrap your css into an object and use ngStyle to bind it to your component rather than the styles attribute, because styles does not support data binding.
Example:
htmlInput: string = "<h1>Why Does Angular make this so hard?</h1>";
cssInput: string = "{h1 { color:red; }}"
Parent Component HTML:
<app-html [html]='htmlInput' [css]='cssInput'></app-html>
Your HTML Component:
import { Component, Input, OnInit } from '#angular/core';
#Component({
selector: 'app-html',
template: '<div [innerHtml]="html" [ngStyle]="css"></div>',
styles: []
})
export class HtmlComponent implements OnInit {
#Input() html: string = "";
#Input() css: string = "";
ngOnInit() {
}
}