Guest User

Parent component not receiving emit from child component

a guest
Sep 7th, 2024
173
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
TypeScript 15.11 KB | Source Code | 0 0
  1. // add-customer-to-class.component.ts:
  2.  
  3. import { Component, OnInit, ViewChild } from '@angular/core';
  4. import { ClassesService } from '../services/classes.service';
  5. import { CommonModule, DatePipe, formatDate } from '@angular/common';
  6. import {
  7.   FormBuilder,
  8.   FormGroup,
  9.   FormsModule,
  10.   ReactiveFormsModule,
  11.   Validators,
  12. } from '@angular/forms';
  13. import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
  14. import { ClassSearchResult } from '../models/classSearchResult';
  15. import { colorChoices } from '../constants/colorChoices';
  16. import { MatCardModule } from '@angular/material/card';
  17. import { MatIconModule } from '@angular/material/icon';
  18. import { MatInputModule } from '@angular/material/input';
  19. import { MatSelectModule } from '@angular/material/select';
  20. import { MatButtonModule } from '@angular/material/button';
  21. import { MatNativeDateModule } from '@angular/material/core';
  22. import { MatFormFieldModule } from '@angular/material/form-field';
  23. import { MatListModule } from '@angular/material/list';
  24. import { MatStepperModule } from '@angular/material/stepper';
  25. import { MatStepper } from '@angular/material/stepper';
  26. import { FlexLayoutModule } from '@angular/flex-layout';
  27. //import moment from 'moment';
  28. import { IconToggleGroupComponent } from '../icon-toggle-group/icon-toggle-group.component';
  29. import { Customer } from '../models/customer';
  30. import { MatDialog } from '@angular/material/dialog';
  31. import { ExistingCustomerModalComponent } from './existing-customer-modal/existing-customer-modal.component';
  32. import { CustomerService } from '../services/customer.service';
  33. import { FileUploadComponent } from '../file-upload/file-upload.component';
  34. import { CustomerAddFormComponent } from '../customers/add-form/customer-add-form.component';
  35.  
  36. @Component({
  37.   selector: 'app-add-customer-to-class',
  38.   standalone: true,
  39.   imports: [
  40.     CommonModule,
  41.     MatCardModule,
  42.     MatIconModule,
  43.     MatInputModule,
  44.     MatListModule,
  45.     MatSelectModule,
  46.     MatButtonModule,
  47.     MatNativeDateModule,
  48.     MatSnackBarModule,
  49.     MatStepperModule,
  50.     FormsModule,
  51.     ReactiveFormsModule,
  52.     MatFormFieldModule,
  53.     FlexLayoutModule,
  54.     IconToggleGroupComponent,
  55.     FileUploadComponent,
  56.     CustomerAddFormComponent,
  57.   ],
  58.   providers: [DatePipe],
  59.   templateUrl: './add-customer-to-class.component.html',
  60.   styleUrl: './add-customer-to-class.component.sass',
  61. })
  62. export class AddCustomerToClassComponent implements OnInit {
  63.   @ViewChild('stepper') private stepper!: MatStepper;
  64.   classes: ClassSearchResult[] = [];
  65.   selectedClass: ClassSearchResult | null = null;
  66.   addCustomerForm: FormGroup;
  67.   colorChoices: string[] = colorChoices;
  68.   classTimeMapping!: { [formattedTime: string]: ClassSearchResult };
  69.   customerId: number | null = null;
  70.   @ViewChild('classImageUpload') classImageUpload!: FileUploadComponent;
  71.   @ViewChild('customerForm') customerForm!: CustomerAddFormComponent;
  72.  
  73.   constructor(
  74.     private classesService: ClassesService,
  75.     private fb: FormBuilder,
  76.     private snackBar: MatSnackBar,
  77.     private datePipe: DatePipe,
  78.     public dialog: MatDialog,
  79.     public customersService: CustomerService
  80.   ) {
  81.     this.addCustomerForm = this.fb.group({
  82.       name: ['', Validators.required],
  83.       phone: ['', Validators.required],
  84.       email: ['', Validators.email],
  85.       color_choice: ['', Validators.required],
  86.     });
  87.   }
  88.  
  89.   createClassTimeMapping() {
  90.     this.classTimeMapping = this.classes.reduce((acc, currentClass) => {
  91.       const formattedTime = this.datePipe.transform(
  92.         currentClass.date,
  93.         'shortTime',
  94.         'UTC'
  95.       );
  96.       if (formattedTime) {
  97.         acc[formattedTime] = currentClass;
  98.       }
  99.       return acc;
  100.     }, {} as { [formattedTime: string]: ClassSearchResult });
  101.   }
  102.  
  103.   ngOnInit(): void {
  104.     this.fetchClassesForToday();
  105.   }
  106.  
  107.   justDate(date: Date) {
  108.     const year = date.getFullYear();
  109.     const month = (date.getMonth() + 1).toString().padStart(2, '0'); // Adding 1 because getMonth() is zero-based
  110.     const day = date.getDate().toString().padStart(2, '0');
  111.  
  112.     return `${month}/${day}/${year}`;
  113.   }
  114.  
  115.   fetchClassesForToday(): void {
  116.     const today = this.justDate(new Date());
  117.     this.classesService.searchClasses({ date: today }).subscribe({
  118.       next: (data) => {
  119.         this.classes = data;
  120.         this.createClassTimeMapping();
  121.       },
  122.       error: (error) => console.error('Error fetching classes', error),
  123.     });
  124.   }
  125.  
  126.   selectClass(formattedTime: string): void {
  127.     this.selectedClass = this.classTimeMapping[formattedTime];
  128.     this.stepper.next();
  129.   }
  130.  
  131.   getFormattedTimes(): (string | null)[] {
  132.     return Object.keys(this.classTimeMapping ?? {});
  133.   }
  134.  
  135.   handleAddExistingCustomer(event: {
  136.     customer: Customer;
  137.     additionalData: any;
  138.   }): void {
  139.     const { customer, additionalData } = event; // Destructure the object
  140.     this.classesService
  141.       .addCustomer(
  142.         customer,
  143.         this.selectedClass!.class_id,
  144.         additionalData.color_choice
  145.       )
  146.       .subscribe({
  147.         next: (classCustomer) => {
  148.           this.snackBar.open('Existing customer added successfully!', 'Close', {
  149.             duration: 5000,
  150.             horizontalPosition: 'center',
  151.             verticalPosition: 'top',
  152.           });
  153.           this.customerId = classCustomer.customer_id;
  154.         },
  155.         error: (err) => {
  156.           console.error(err);
  157.           this.snackBar.open('Failed to add existing customer.', 'Close', {
  158.             duration: 5000,
  159.             horizontalPosition: 'center',
  160.             verticalPosition: 'top',
  161.           });
  162.         },
  163.       });
  164.   }
  165.  
  166.   handleTest(foo: string): void {
  167.     debugger;
  168.   }
  169.  
  170.   handleAddNewCustomer(event: {
  171.     name: string;
  172.     phone: string;
  173.     email: string;
  174.     receive_text: boolean;
  175.     receive_email: boolean;
  176.     additionalData: any;
  177.   }): void {
  178.     const { name, phone, email, receive_text, receive_email, additionalData } =
  179.       event;
  180.     this.classesService
  181.       .addNewCustomer(
  182.         name,
  183.         phone,
  184.         email,
  185.         receive_text,
  186.         receive_email,
  187.         additionalData.color_choice,
  188.         this.selectedClass!.class_id
  189.       )
  190.       .subscribe({
  191.         next: (classCustomer) => {
  192.           this.snackBar.open('Customer added successfully!', 'Close', {
  193.             duration: 5000,
  194.             horizontalPosition: 'center',
  195.             verticalPosition: 'top',
  196.           });
  197.           this.customerId = classCustomer.customer_id;
  198.         },
  199.         error: (err) => {
  200.           console.error(err);
  201.           this.snackBar.open('Failed to add customer.', 'Close', {
  202.             duration: 5000,
  203.             horizontalPosition: 'center',
  204.             verticalPosition: 'top',
  205.           });
  206.         },
  207.       });
  208.   }
  209.  
  210.   complete(): void {
  211.     let continueWithoutImages = true;
  212.     let addAnother = false;
  213.     if (!this.classImageUpload.images.length) {
  214.       continueWithoutImages = confirm(
  215.         "You haven't uploaded any images. Are you sure you want to continue?"
  216.       );
  217.     }
  218.     if (continueWithoutImages) {
  219.       addAnother = confirm(
  220.         "You're all set! We'll text you when your piece is ready to pick up! Would you like to add another class member?"
  221.       );
  222.     }
  223.     if (addAnother) {
  224.       this.addCustomerForm.reset();
  225.       this.customerId = null;
  226.       this.stepper.selectedIndex = 1;
  227.     }
  228.   }
  229. }
  230.  
  231. // add-customer-to-class.html:
  232. <ng-container *ngIf="classes.length > 0; else noClassesFound">
  233.   <mat-vertical-stepper linear #stepper="matVerticalStepper">
  234.     <mat-step>
  235.       <ng-template matStepLabel>Select your class (start time)</ng-template>
  236.       <icon-toggle-group
  237.         [values]="getFormattedTimes()"
  238.         (change)="selectClass($event)"
  239.       >
  240.       </icon-toggle-group>
  241.     </mat-step>
  242.     <mat-step [stepControl]="addCustomerForm">
  243.       <ng-template matStepLabel>Add your details</ng-template>
  244.       <customer-add-form #customerForm>
  245.         (addExistingCustomer)="handleAddExistingCustomer($event)"
  246.         (addNewCustomer)="handleAddNewCustomer($event)"
  247.         (testFunc)="handleTest($event); console.log('Parent template capturing
  248.        event:', $event)" >
  249.         <ng-template #colorChoiceField let-formGroup="formGroup">
  250.           <mat-form-field appearance="fill">
  251.             <mat-label>Color Choice</mat-label>
  252.             <mat-select
  253.               [formControl]="formGroup.controls['color_choice']"
  254.               required
  255.             >
  256.               <mat-option *ngFor="let color of colorChoices" [value]="color">
  257.                 {{ color }}
  258.               </mat-option>
  259.             </mat-select>
  260.           </mat-form-field>
  261.         </ng-template>
  262.         <div custom-buttons>
  263.           <button
  264.             mat-raised-button
  265.             color="primary"
  266.             type="submit"
  267.             [disabled]="customerForm.addCustomerForm.invalid"
  268.           >
  269.             Add Me
  270.           </button>
  271.         </div>
  272.       </customer-add-form>
  273.       <div #testDiv>Test Div Content</div>
  274.     </mat-step>
  275.     <mat-step>
  276.       <ng-template matStepLabel>Upload a picture of your piece</ng-template>
  277.  
  278.       <file-upload
  279.         #classImageUpload
  280.         *ngIf="selectedClass && customerId"
  281.         imageType="classCustomer"
  282.         [objectIds]="[selectedClass.class_id, customerId]"
  283.       >
  284.       </file-upload>
  285.       <br />
  286.       <button mat-raised-button color="primary" (click)="complete()">
  287.         Finish
  288.       </button>
  289.     </mat-step>
  290.   </mat-vertical-stepper>
  291. </ng-container>
  292. <ng-template #noClassesFound>
  293.   <p>No classes found today.</p>
  294. </ng-template>
  295.  
  296. // customer-add-form.component.ts:
  297. import {
  298.   Component,
  299.   EventEmitter,
  300.   Input,
  301.   Output,
  302.   OnInit,
  303.   ContentChild,
  304.   TemplateRef,
  305.   ViewChild,
  306. } from '@angular/core';
  307. import {
  308.   FormBuilder,
  309.   FormControl,
  310.   FormGroup,
  311.   ReactiveFormsModule,
  312.   Validators,
  313. } from '@angular/forms';
  314. import { CustomerService } from '../../services/customer.service';
  315. import { ClassSearchResult } from '../../models/classSearchResult';
  316. import { colorChoices } from '../../constants/colorChoices';
  317. import { Customer } from '../../models/customer';
  318. import { MatFormFieldModule } from '@angular/material/form-field';
  319. import { CommonModule } from '@angular/common';
  320. import { MatCheckboxModule } from '@angular/material/checkbox';
  321. import { MatSelectModule } from '@angular/material/select';
  322. import { MatInputModule } from '@angular/material/input';
  323.  
  324. @Component({
  325.   selector: 'customer-add-form',
  326.   standalone: true,
  327.   imports: [
  328.     ReactiveFormsModule,
  329.     MatFormFieldModule,
  330.     CommonModule,
  331.     MatCheckboxModule,
  332.     MatSelectModule,
  333.     MatInputModule,
  334.   ],
  335.   templateUrl: './customer-add-form.component.html',
  336.   styleUrls: ['./customer-add-form.component.sass'],
  337. })
  338. export class CustomerAddFormComponent implements OnInit {
  339.   @Output() customerAdded = new EventEmitter<number>();
  340.   @Output() addExistingCustomer = new EventEmitter<{
  341.     customer: Customer;
  342.     additionalData: any;
  343.   }>();
  344.   @Output() addNewCustomer = new EventEmitter<{
  345.     name: string;
  346.     phone: string;
  347.     email: string;
  348.     receive_text: boolean;
  349.     receive_email: boolean;
  350.     additionalData: any;
  351.   }>();
  352.   @Output() testFunc = new EventEmitter();
  353.   @ContentChild('additionalFields') additionalFields!: TemplateRef<any>; // Injected custom fields
  354.   @ViewChild('templateControls') templateControls!: any;
  355.  
  356.   addCustomerForm!: FormGroup;
  357.   colorChoices: string[] = colorChoices;
  358.   @Input() additionalFieldsTemplate!: any;
  359.   constructor(
  360.     private fb: FormBuilder,
  361.     private customersService: CustomerService
  362.   ) {}
  363.  
  364.   ngOnInit(): void {
  365.     this.addCustomerForm = this.fb.group({
  366.       name: ['', Validators.required],
  367.       phone: ['', Validators.required],
  368.       email: ['', Validators.email],
  369.       receive_text: [true],
  370.       receive_email: [true],
  371.       agree_terms: [false, Validators.requiredTrue],
  372.     });
  373.     console.log('Child component initialized');
  374.   }
  375.  
  376.   ngAfterViewInit(): void {
  377.     this.addAdditionalFields();
  378.     console.log('Child component View initialized');
  379.   }
  380.  
  381.   addAdditionalFields(): void {
  382.     if (this.templateControls) {
  383.       // Iterate over each field passed through the template
  384.       this.templateControls.forEach((control: any) => {
  385.         const controlName = control.name;
  386.         const isRequired = control.required;
  387.  
  388.         const validators = isRequired ? [Validators.required] : [];
  389.         this.addCustomerForm.addControl(
  390.           controlName,
  391.           new FormControl('', validators)
  392.         );
  393.       });
  394.     }
  395.   }
  396.  
  397.   testEmit(): void {
  398.     console.log('Child emitting testFunc event:', 'test');
  399.     this.testFunc.emit('test');
  400.   }
  401.  
  402.   addCustomer(): void {
  403.     if (this.addCustomerForm.valid) {
  404.       const { name, phone, email, receive_text, receive_email } =
  405.         this.addCustomerForm.value;
  406.       const additionalData = this.getAdditionalData();
  407.       this.customersService.searchByPhone(phone).subscribe({
  408.         next: (existingCustomer: Customer) => {
  409.           // Handle the case when the customer exists
  410.           this.addExistingCustomer.emit({
  411.             customer: existingCustomer,
  412.             additionalData,
  413.           });
  414.           this.testFunc.emit('poo');
  415.         },
  416.         error: () => {
  417.           // Handle the case when the customer doesn't exist
  418.           this.addNewCustomer.emit({
  419.             name,
  420.             phone,
  421.             email,
  422.             receive_text,
  423.             receive_email,
  424.             additionalData,
  425.           });
  426.         },
  427.       });
  428.     }
  429.   }
  430.  
  431.   getAdditionalData(): any {
  432.     const {
  433.       name,
  434.       phone,
  435.       email,
  436.       receive_text,
  437.       receive_email,
  438.       agree_terms,
  439.       ...additionalData
  440.     } = this.addCustomerForm.value;
  441.     return additionalData;
  442.   }
  443. }
  444.  
  445. // customer-add-form.component.html:
  446. <form [formGroup]="addCustomerForm" (ngSubmit)="addCustomer()">
  447.   <mat-form-field appearance="fill">
  448.     <mat-label>Name</mat-label>
  449.     <input matInput formControlName="name" placeholder="Name" required />
  450.   </mat-form-field>
  451.  
  452.   <mat-form-field appearance="fill">
  453.     <mat-label>Phone</mat-label>
  454.     <input matInput formControlName="phone" placeholder="Phone" />
  455.   </mat-form-field>
  456.  
  457.   <mat-form-field appearance="fill">
  458.     <mat-label>Email</mat-label>
  459.     <input matInput formControlName="email" placeholder="Email" />
  460.   </mat-form-field>
  461.  
  462.   <ng-container *ngIf="additionalFields">
  463.     <ng-container
  464.       *ngTemplateOutlet="
  465.        additionalFields;
  466.        context: { formGroup: addCustomerForm }
  467.      "
  468.     ></ng-container>
  469.   </ng-container>
  470.  
  471.   <mat-checkbox formControlName="receive_text"
  472.     >Receive Text Messages</mat-checkbox
  473.   >
  474.  
  475.   <!-- Receive Email Checkbox -->
  476.   <mat-checkbox formControlName="receive_email">Receive Emails</mat-checkbox>
  477.  
  478.   <!-- Agree to Terms and Conditions Checkbox -->
  479.   <mat-checkbox formControlName="agree_terms">
  480.     I agree to the
  481.     <a href="/terms.html" target="_blank">Terms of Service</a> and
  482.     <a href="/privacy.html" target="_blank">Privacy Policy</a>
  483.   </mat-checkbox>
  484.  
  485.   <ng-content select="[custom-buttons]"></ng-content>
  486. </form>
  487. <button (click)="testEmit()">test</button>
  488.  
Advertisement
Add Comment
Please, Sign In to add comment