How to add an Emoji Picker to Angular App (Angular 12) - html

I created a app clone Instagram to learn Angular. I wanna add a button while clicked will show a popup that contains icon list to use in comment.

I found a solution myself.
<div (keyup.enter)="postComment()" class="container_comment">
<button (click)="isEmojiPickerVisible = !isEmojiPickerVisible;"><img src="assets/icons/smile-success-32.png"
width="28" height="28" alt=""></button>
<input type="text" placeholder="Add a comment..."
[(ngModel)]="comment"/>
<emoji-mart class="emoji-mart" *ngIf="isEmojiPickerVisible" (emojiSelect)="addEmoji($event)"
title="Choose your emoji"></emoji-mart>
</div>
and typeScript file add this
public isEmojiPickerVisible: boolean;
public comment: string = '';
public addEmoji(event: { emoji: { native: any; }; }) {
this.comment = `${this.comment}${event.emoji.native}`;
this.isEmojiPickerVisible = false;
}

Related

Make custom file upload angular component required in the form

I have created a custom file upload angular component and I am using it in a template driven form. The form contains angular material components. I want this custom component to be required with the template driven form.
This is the html code for the custom component:
<input type="file" class="file-input" (change)="onFileSelected($event.target.files[0])" #fileUpload>
<div class="file-upload">
<button type="button" mat-mini-fab color="primary" class="upload-btn" (click)="fileUpload.click()">
<mat-icon>attach_file</mat-icon>
</button>
{{uploadedFileName || "Choose a file."}}
</div>
The typescript code:
uploadedFileName = "";
#Output() onUploadFileEvent = new EventEmitter<File>();
constructor() { }
ngOnInit(): void {
}
onFileSelected(uploadedFile: File) {
if (uploadedFile) {
this.uploadedFileName = uploadedFile.name;
this.onUploadFileEvent.emit(uploadedFile);
}
}
And I am using the component like this in the form:
<app-file-uploader (onUploadFileEvent)="uploadFile($event)"></app-file-uploader>
How can I make this custom component required and prevent the user from submitting the form if a file is not yet selected ?
Thanks;

Angular add toggle switch inside datepicker calendar

Is it possible to add the toggle switch inside the calender? I want to put it at the top of the calender when the calendar is open so the user can choose to show date details by the toggle switch
<form #uploadForm="ngForm" (keydown.enter)="$event.preventDefault()">
<div class="input-wrapper">
<mat-form-field>
<input
id="date"
name="date"
[disabled]="datePickerDisabled || uploadForm.submitted"
[matDatepicker]="datepicker"
placeholder="Expiration date"
autocomplete="off"
matInput
required />
<mat-datepicker-toggle matSuffix [for]="datepicker"></mat-datepicker-toggle>
<mat-datepicker touchUi #datepicker></mat-datepicker>
</mat-form-field>
<div class="tooltip">This field is required.</div>
<mat-slide-toggle
(change)="setMaxExpirationDate($event)">Show Date Details</mat-slide-toggle>
</div>
</form>
I think you has two aproachs
1.-Customize the header, see the docs:customizing header
From this SO answer. replicate the header:
/** Custom header component for datepicker. */
#Component({
selector: 'example-header',
template: `
<mat-slide-toggle
(change)="setMaxExpirationDate($event)">Show Date Details</mat-slide-toggle>
<div class="mat-calendar-controls">
<button mat-button type="button" class="mat-calendar-period-button"
(click)="currentPeriodClicked()" [attr.aria-label]="periodButtonLabel"
cdkAriaLive="polite">
{{periodButtonText}}
<div class="mat-calendar-arrow"
[class.mat-calendar-invert]="calendar.currentView != 'month'"></div>
</button>
<div class="mat-calendar-spacer"></div>
<ng-content></ng-content>
<button mat-icon-button type="button" class="mat-calendar-previous-button"
[disabled]="!previousEnabled()" (click)="previousClicked()"
[attr.aria-label]="prevButtonLabel">
</button>
<button mat-icon-button type="button" class="mat-calendar-next-button"
[disabled]="!nextEnabled()" (click)="nextClicked()"
[attr.aria-label]="nextButtonLabel">
</button>
</div>
</div> `,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ExampleHeader extends MatCalendarHeader<any> {
/** Handles user clicks on the period label. */
currentPeriodClicked(): void {
this.calendar.currentView = this.calendar.currentView == 'month' ? 'multi-year' : 'month';
}
}
(change the .html to add the controls you want)
2.-Enclose the mat-datepicker in a mat-menu, like it showed in this another SO answer
Updated Access to an element of header it's not very easy. but control the toogle in easy if we use an intermediate service
Imagine you has a service like
#Injectable({
providedIn: "root"
})
export class CalendarService {
private _event = new Subject<void>();
public onEvent = this._event as Observable<any>;
constructor() {}
command(value: any) {
this._event.next(value);
}
}
You can inject the service in the constructor of customHeader
constructor(
private _calendar: MatCalendar<D>,
private _dateAdapter: DateAdapter<D>,
#Inject(MAT_DATE_FORMATS) private _dateFormats: MatDateFormats,
cdr: ChangeDetectorRef,
private service: CalendarService
)
Then, if our toogle call a function
<mat-slide-toggle #toogle (change)="toogleChange($event)">
Show Date Details
</mat-slide-toggle>
The function becomes like
toogleChange(event: any) {
this.service.command(event);
}
Just in ngOnInit in the component subscribe to the service
ngOnInit() {
this.service.onEvent.subscribe(res => {
console.log(res.checked);
});
}
You can see in stackblitz

Problems with Angular Dynamic Reactive Form

I'm trying to create a dynamic reactive form. The user has the ability to choose between either a text (type = 1) input or img (type = 2) input. According to his choice, the right input is being added. - He can add as much input field as he wants.
I've never really used reactive forms before, hence this question.
The code below adds a control according to what module the user has chosen, but for instance adding a textarea only displays a textarea with [object Object] inside - clicking makes it disappear.
Additionally I haven't figured out yet how to submit the form's input. Logging form on submit returns the form, but without the textarea's input.
That's what I have so far:
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<div *ngFor="let module of form.get('modules').controls; let i = index" class="position-relative" [style.padding-bottom.rem]="paddingValue" (mouseover)="showPaddingInput = true" formArrayName="modules">
<div class="padding-input position-absolute d-flex justify-content-center" *ngIf="showPaddingInput === true" [style.height.rem]="paddingValue">
<input type="text" class="align-self-center text-center padding-input-field" [value]="paddingValue" (input)="changePadding(padding.value)" #padding>
</div>
<div class="text" *ngIf="module.value.type === 1">
<textarea class="flow-text" placeholder="Some Text..." rows="3" [formControlName]="i"></textarea>
</div>
<div class="img-container" *ngIf="module.value.type === 2">
<div class="custom-file align-self-center">
<input type="file" id="i" class="custom-file-input" [formControlName]="i" (change)="handleFileInput($event.target.files)">
<label class="custom-file-label" for="i"></label>
</div>
</div>
</div>
<button class="btn btn-dark">Submit</button>
</form>
export class CreateCaseCmsComponent implements OnInit {
form: FormGroup;
constructor(private caseService: CasesService) { }
addModule(type) {
if (type === 1) {
const control = new FormControl({type: 1}, Validators.required);
(this.form.get('modules') as FormArray).push(control);
} else if (type === 2) {
const control = new FormControl({type: 2}, Validators.required);
(this.form.get('modules') as FormArray).push(control);
}
}
ngOnInit() {
this.form = new FormGroup({
modules: new FormArray([])
});
}
onSubmit() {
console.log(this.form);
}
}
the first argument to a form control is it's value, so you're setting the initial value as an object and that's why it's showing [object Object] in the text box... that's what you get if you call .toString() on an object, you need to instantiate them like this:
const control = new FormControl('', Validators.required);
or something like that... this affects how you're building your template, so you probably need something more like:
const group = new FormGroup({
type: new FormControl(1),
value: new FormControl('', Validators.required)
});
and add that group to your array and access it like:
<div class="text" *ngIf="module.get('type').value === 1" [formGroupName]="i">
<textarea class="flow-text" placeholder="Some Text..." rows="3" formControlName="value"></textarea>
</div>

Is there an onHidden event for the ngb-datepicker? If there isn't how do we add events to custom components in angular?

I am using the datepicker from this source: https://ng-bootstrap.github.io/#/components/datepicker/api
And I would like to check if the ngb-datepicker is closed because I need to change the text of the button where it is triggered.
template:
<button (click)="dp.open(); changeText();">{{buttonText}}</button>
<ngb-datepicker #dp
[(ngModel)]="model"
(onHidden)="changeButtonText2()" <<---is this possible? >
/>
ts:
import {Component} from '#angular/core';
import {NgbCalendar} from '#ng-bootstrap/ng-bootstrap';
#Component({
selector: 'ngbd-datepicker-basic',
templateUrl: './datepicker-basic.html'
})
export class NgbdDatepickerBasic {
buttonText: string = 'Open Calendar'
constructor(private calendar: NgbCalendar) {
}
changeText() {
this.buttonText = 'The Calendar is Open';
}
changeButtonText2() {
this.buttonText = 'Open Calendar'
}
}
The ngx-bootstrap datepick have this but it seems the ngb-datepicker does not implement this feature. Can someone help me create a workaround so I don't have to use the ngx-bootstrap just for this? I already added some styling so...
Thanks :)
If you are using popup datepicker and only want to change text button
<form class="form-inline">
<button (click)="dpk.toggle()">{{ dpk.isOpen() ? 'The Calendar is Open' : 'Open Calendar' }}</button>
<div class="form-group">
<input class="form-control" placeholder="yyyy-mm-dd"
name="dp" [(ngModel)]="model" ngbDatepicker #dpk="ngbDatepicker">
</div>
</form>
if you want to custom more code, use this:
#ViewChild('dpk') dpk: NgbDatepicker;
ngAfterViewInit() {
this.dpk['close'] = () => {
if (this.dpk['isOpen']) {
// super origin event
this.dpk['_vcRef'].remove(this.dpk['_vcRef'].indexOf(this.dpk['_cRef'].hostView));
this.dpk['_cRef'] = null;
this.dpk['_closed$'].next();
// custom code
console.log('closed');
}
};
}

Angular 4/5 material raised button with input file

I am working on a angular application, currently to upload a file I am using this :
<label class="btn btn-default">
<input type="file" (change)="selectFile($event)">
</label>
<button class="btn btn-success" [disabled]="!selectedFiles"
(click)="upload()">Upload</button>
with methods on my .ts file, it is working well.
I want to upgrade this to material angular components raised button like that right now :
<button mat-raised-button>
<input type="file" (change)="selectFile($event)">
</button>
<button mat-button disabled [disabled]="!selectedFiles" (click)="upload()">Upload</button>
the disabled button is doing well but the input file part doesnt work , it prints baddly and does not open a file folder search window. any ideas?
Won't advise using input field within a button, better you hide the file input and then a button to trigger it. The below example will show a minimal example of it
#Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}} is for Uploading</h2>
</div>
<button mat-raised-button (click)="openInput()">
Select File to Upload
</button>
<input id="fileInput" hidden type="file" (change)="fileChange($event.target.files)" >
<button mat-button [disabled]="!ourFile" (click)="upload()">Upload</button>
`
})
export class App {
name:string;
ourFile: File; // hold our file
constructor() {
this.name = `Angular! v${VERSION.full}`
}
/**
* this is used to trigger the input
*/
openInput(){
// your can use ElementRef for this later
document.getElementById("fileInput").click();
}
fileChange(files: File[]) {
if (files.length > 0) {
this.ourFile = files[0];
}
}
/**
* this is used to perform the actual upload
*/
upload() {
console.log('sending this to server', this.ourFile);
}
}
Check this plnk
With the above example, you should be able to style your button without distorting HTML semantics