Make custom file upload angular component required in the form - html

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;

Related

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

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;
}

Router navigation & modal close

I'm using a form component within 2 separate components in an Angular project. When the user selects 'Save' I would like my onSubmit function to close a modal if it's in one of the components or use the router link if it's in another.
I currently have my onSubmit function to finish with the router link as shown below:
async onSubmit() {
this.router.navigate(['/home']);
}
But I would also like this to include closing a modal and not navigating when the user is in a different component.
<div class="modal-body">
<app-add-form></app-drug-audit-add-form>
</div>
I used a form handler and linked this to the function.
HTML
<app-add-form (saveFormHandler)="onSave()"></app-add-form>
TS (first file)
#Output()
saveFormHandler = new EventEmitter();
onSubmit() {
this.saveFormHandler.emit();
this.saveFormHandler2.emit();
}
TS (second file)
onSave() {
this.router.navigate(['/drug-audit']);
}
TS (third file)
onSave() {
this.modalRef.hide();
}

Validation using if statement using input binding in Angular

I am creating a reusable component for Input field. I created a Boolean tag named "IsValid" inside my typescript file to show validation message.
My typescript file
export class InputControlsComponent implements OnInit {
#Input() IsValid;
#Input() className;
#Input() controlName;
#Input() inputType;
constructor() { }
ngOnInit() {
}
}
Html File
<div>
<input type="{{inputType}}" class="{{className}}" >
<span class="error-message" *ngIf="!IsValid">This Field is required</span>
</div>
How it is being used
<div>
<label>Name</label>
<app-input-controls inputType="text" controlName="Address" className="form-control" IsValid = "false">
</app-input-controls>
</div>
I am able to change the value of the Boolean tag of typescript file but the error message is not changing on change of the Boolean tag.
You can use ngModel like [(IsValid)],
If you use ngModel,your model is binding two way.
For example set your html
<app-input-validation [inputType]="'text'" [controlName]="Address" [className]="form-control" [(IsValid)]="isValidDate">
</app-input-validation>
You can set isValid property on parent component whenever you want.
Only write this.isValidText=true;
Please examine example
change !IsValid to IsValid. it will work
<div>
<input type="{{inputType}}" class="{{className}}" >
<span class="error-message" *ngIf="IsValid">This Field is required</span>
</div>

Changing values of a counter variable in Angular

I have 2 buttons on my login page, Button1 and Button2. Both the buttons direct to the same URL page. But on clicking Button 2, I want to disable the functionality of Button 3 which is on the next URL page.
Button 3 should be accessed only when Button 1 was clicked on the main page.
Here's the HTML code of the main page. Button 1 is a part of the ngForm.
<button class="btn btn-primary" id="alert" type="submit">Login</button>
<button class="btn-primary" routerLink="/login/olduser" id="logins">Patient Login</button>
Here's the HTML code of Second page.
<button class="btn btn-primary" style ='margin-left: 700px;'routerLink="../../login/newuser">Register a new patient </button>
One possible solution I thought of was exporting a counter variable from the main page to the second page on clicking Button 2, which will inform to disable Button 3, but I failed to do so.
How can I implement this functionality?
Here's what I have tried till now :
<button class="btn-primary" (Click)="newUser()" id="logins">Patient Login</button>
public newUser(){
var status="success";
console.log(status);
this.router.navigateByUrl('/login/olduser');
}
I'm trying to print the value of "status" on console, to check if the method is being accessed but there's no output on console and also the url doesn't change.
I want to call this "status" variable in olduser.ts script.
It seems you're trying to limit the functionality of some sort of dashboard depending on user type (patient, non-patient).
I don't think you should rely on a referrer button at all here.
I'd send something like a list of permissions for user to client app after logging in and wrap it in a AuthorizationService of some kind. Then I'd check if the user has the permission to register a new patient and show/hide the corresponding button.
Of course, you shouldn't forget about server-side validation for registration requests.
UPD: if one of the user types doesn't distinguish between users and doesn't require server-side authentication, you can just generate some kind of default set of permissions in the service for those non-privileged users and keep the display logic for page 2 based on permission checks.
On Click of button pass a query parameter. Then on the next page read the value of the query parameter from URL and disable the button 3 based on the value.
Working Demo
Homepage HTML
<a routerLink='/page1' [queryParams]="{button: 'a'}"><button>button 1</button></a>
<a routerLink='/page1' [queryParams]="{button: 'b'}"><button>button 2 </button></a>
<router-outlet></router-outlet>
In the routed component .TS
import { Component, Input, OnInit } from "#angular/core";
import { ActivatedRoute } from "#angular/router";
#Component({
selector: "hello",
template: `
<h1>Hello {{ name }}!</h1>
<button [disabled]="isDisable">button3</button>
`,
styles: [
`
h1 {
font-family: Lato;
}
`
]
})
export class HelloComponent implements OnInit {
#Input() name: string;
isDisable: boolean;
constructor(private activatedRoute: ActivatedRoute) {}
ngOnInit() {
this.activatedRoute.queryParams.subscribe(params => {
this.isDisable = params.button === "a";
});
}
}
You can send the state of the button as a query parameter on button 2 click. Now, On the new page get the query params value and then apply property binding.
On Button 2 click :
this.router.navigate(['/newpage'], { queryParams: { state: "false"});
Now, on new page add as below :
import { ActivatedRoute } from '#angular/router'
export class newPage implements OnInit {
btnState
constructor(private route: ActivatedRoute) { }
ngOnInit() {
this.route.queryParams
.filter(params => params.state)
.subscribe(params => {
this.btnState = params
});
}
Now,apply property binding to the button
<button [disabled]="btnState">Button3</button>
There is multiple ways to achieve what you try to do:
With the click on Button 2, you can store in a service, a variable isActive to false and in your next url/Component, check from the service the variable to disabled or not your Button 3.
Navigate to your url with a params: my-new-url?ACTIVE=false, and in your new url/component, check the url to find the Params and disable your button according to the value

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