troubleshooting Question

Angular JS Support Tool - Make File Attachment Option - Not Required

Avatar of Adam Ehrenworth
Adam EhrenworthFlag for United States of America asked on
JavaScriptMicrosoft SharePointAngular
5 Comments1 Solution166 ViewsLast Modified:
I was handed over a support tool by our contractor that is based on Angular JS. I have some basic understanding of how it functions, but I am having trouble turning off a check on a particular module that is required that an attachment is included before the form can be submitted to a SharePoint list. I have included the code for the HTML as well as the associated code files. Please advise what need to be changed to allow for an attachment to be included but NOT have it be required.

HTML
<!--removed this from submit button [disabled]='!trgIssueForm.valid'-->
<div [@routerTransition] class="panel panel-primary">
    <!--<h2>Request Management- <small>{{_requestService?._selReq?.Title}}</small></h2>-->
    <div class="panel-heading">
        {{_requestService?._selReq?.Title}}
    </div>
    <!--<hr>-->
    <div class="panel-body">
        <form class="form-horizontal"
              novalidate
              (ngSubmit)="saveRequest()"
              [formGroup]="trgIssueForm" >
            <fieldset>
                <div class="checkbox">
                    <label class="formyself">
                        <input type="checkbox" formControlName="MyRequest">This request is for myself
                    </label>
                </div>
                <div class="form-group">
                    <mat-form-field class="col-md-6">
                        <input matInput class="form-control" 
                                id="requesterWWIDId" 
                                type="text" 
                                placeholder="WWID" 
                                value={{_impUser?.WWID}}
                                formControlName="RequesterWWID" />
                                <mat-hint align="start">{{_impUser?.RequesterName}}</mat-hint>
                    </mat-form-field>
                </div>
                <!--<div class="form-group">
                    <mat-form-field class="col-md-6">
                        <input matInput class="form-control" 
                                id="RequesterName" 
                                type="text" 
                                placeholder="Requester Name" 
                                value={{_impUser?.RequesterName}}
                                formControlName="RequesterName" />
                    </mat-form-field>
                </div>-->
                <div class="form-group">
                    <mat-form-field class="col-md-6">
                        <mat-select class="form-control"
                            id="ReqActSelect" 
                            placeholder="Select Issue Type"
                            formControlName="ReqActSelect">
                            <mat-option value="TrainingIssue">Completion issue</mat-option>
                            <mat-option value="TrainingIssue">Training not working</mat-option>
                            <mat-option value="TrainingIssue">Other</mat-option>
                            <!--<mat-option value="WhyTrg">Why did I get this assigned?</mat-option>-->
                        </mat-select>
                    </mat-form-field>
                </div>
                <div class="form-group">
                    <mat-form-field class="col-md-6">
                        <input matInput [matAutocomplete]="auto"
                                class="form-control" 
                                id="trainingId" 
                                type="text" 
                                placeholder="Training"
                                formControlName="Training" />
                                <mat-autocomplete #auto="matAutocomplete">
                                    <mat-option *ngFor="let trg of filteredTrainings | async" [value]="trg.TrainingCode">
                                        <span>Title: {{trg.Title}}</span> | Code: <span>{{ trg.TrainingCode }}</span>
                                    </mat-option>
                                </mat-autocomplete>
                    </mat-form-field>
                </div>
                <div class="form-group" [hidden]="_hideScreenshot">
                    <div class="col-md-6">
                        <input class="form-control file-attach" 
                            id="Screenshot" 
                            type="file" 
                            aria-describedby="fileHelp"
                            placeholder="Attache Screenshot" 
                            accept=".jpeg, .png"
                            formControlName="Screenshot" />
                        <!--<p *ngIf="trgIssueForm.controls.Screenshot.errors?.required" style="color: red">Screenshot is required!</p>-->
                        <label class="file-attach-label">
                            Attach a Screenshot
                        </label>
                    </div>
                </div>
                <div class="form-group">
                    <mat-form-field class="col-md-6">
                        <textarea matInput class="form-control" 
                                id="requestDescriptionId" 
                                placeholder="Description"
                                rows=3
                                formControlName="RequestDescription"></textarea>
                    </mat-form-field>
                </div>
                <div class="form-group">
                    <div class="col-md-4 col-md-offset-2">
                        <span>
                            <button mat-raised-button class="btn btn-primary"
                                    type="submit"
                                    style="width:80px;margin-right:10px"
                                    >
                                Submit
                            </button>
                        </span>
                        <span>
                            <a class="btn btn-default"
                               style="width:80px"
                               (click)="cancelRequest()">
                                Cancel
                            </a>
                        </span>
                     </div>
                </div>
            </fieldset>
        </form>
        <div class='has-error' style="color: red" *ngIf='errorMessage'>{{errorMessage}}</div>
    </div>
    <!--<ngb-alert [type]="alert.type" (close)="closeAlert(alert)" *ngFor="let alert of alerts">{{ alert.message }}</ngb-alert>-->
</div>

TS Components
import { Component, OnInit, AfterViewInit, OnDestroy, ViewChildren, ElementRef, Input } from '@angular/core';
import { FormBuilder, FormGroup, FormControl, FormArray, Validators, FormControlName } from '@angular/forms';
import { routerTransition } from '../../router.animations';
import { RequestService, FileValidator } from 'app/core';
import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
import { GenericValidator } from '../../shared/generic-validator';
import { TrgIssueService } from './trgissue.service';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import {startWith} from 'rxjs/operators/startWith';

import { DISABLED } from '@angular/forms/src/model';
import { HttpClient } from '@angular/common/http';
import { IImpUser } from 'app/reqmgmt/dtos';
import { map, filter, debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators';

@Component({
  selector: 'app-req-whytrg',
  templateUrl: './trgissue.component.html',
  animations: [routerTransition()]
})
export class TrgIssueComponent implements OnInit {

  currentUrl: string;
  @ViewChildren(FormControlName, { read: ElementRef }) formInputElements: ElementRef[];

  // pageTitle = 'Product Edit';
  // errorMessage: string;
  trgIssueForm: FormGroup;
  selTraining: any = null;
  public errorMessage = null;
  public _hideScreenshot = true;
  public _impUser: IImpUser = <IImpUser>{};
  // private sub: Subscription;
  MyRequest: FormControl = new FormControl();
  private isMyrequest = true;
  // MyRerequesterWWIDId: FormControl = new FormControl();
  // Use with the generic validation message class
  // displayMessage: { [key: string]: string } = {};
  // private validationMessages: { [key: string]: { [key: string]: string } };
  private genericValidator: GenericValidator;
  filteredTrainings: Observable<any[]>;
  constructor(private _router: Router, public _requestService: RequestService,
    private fb: FormBuilder,
    private _http: HttpClient,
    private route: ActivatedRoute,
    private router: Router,
    private _trgIssueService: TrgIssueService ) {
      _router.events.subscribe((event) => {
        if (event instanceof NavigationEnd ) {
            this.currentUrl = event.url;
            console.log('TrgIssueComponent- constructor - this.currentUrl', this.currentUrl);
        }
    });
    // this.genericValidator = new GenericValidator(this.validationMessages);
  }
  filterTrainings(TrainingCode: string) {
    console.log('TrgIssueComponent -> filterTrainings: TrainingCode', TrainingCode);
      return this._requestService._distTrgs.filter(trg =>
        trg.TrainingCode.toLowerCase().indexOf(TrainingCode.toLowerCase()) === 0);
  }
  buildForm() {
    this.trgIssueForm = this.fb.group({
      MyRequest: true,
      RequesterWWID: new FormControl(this._impUser.WWID, {
        validators: [Validators.required], updateOn: 'blur'}),
      // RequesterName: new FormControl(this._impUser.RequesterName, {
      //  validators: [Validators.required], updateOn: 'blur'}),
      ReqActSelect: ['', Validators.required],
      Screenshot: ['', FileValidator.validate],
      Training: ['', Validators.required],
      RequestDescription: ''
    });
  }
  ngOnInit() {
    console.log('TrgIssueComponent Component OnInit');
    this.setImpUserToDefault();
    // If user directly came to thispage, we need to get Selected Request Item
    if ( !this._requestService._selReq) {
      // filter this request type from reqTypes collection
      this._requestService._selReq = Object.assign({}, this._requestService._requestTypes.filter(req =>
        req.ReqLink === this.currentUrl)[0]);
        console.log('TrgIssueComponent->ngOnInit-_selReq',  this._requestService._selReq);
    }
    // get all the data
    // this._requestService.getTrainings();
    this.buildForm();
    this.trgIssueForm.get('RequesterWWID').disable();
    // this.trgIssueForm.get('RequesterName').disable();
    this.filteredTrainings = this.trgIssueForm.get('Training').valueChanges
      .pipe(
        startWith(''),
        map(trg => trg ? this.filterTrainings(trg) : this._requestService._distTrgs)
      );
    this.trgIssueForm.get('MyRequest').valueChanges
        .subscribe(value => this.onChangeMyRequest(value));
    this.trgIssueForm.get('ReqActSelect').valueChanges
    .subscribe(value => this.onReqActionChange(value));
    this.trgIssueForm.get('RequesterWWID').valueChanges.
      subscribe(inputval => {
        console.log('TrgIssueComponent->ngOnInit- getWWIDDataByWWID -> inputval', inputval );
        if (!this.trgIssueForm.get('MyRequest').value) {
          this._requestService.getWWIDDataByWWID(inputval).then(res => {
            console.log('TrgIssueComponent->ngOnInit- getWWIDDataByWWID -> res', res);
            if (res && res.length === 1 ) {
              const tUser: IImpUser = <IImpUser>{};
              tUser.WWID = res[0].Title;
              tUser.RequesterName = res[0].FirstName + ' ' + res[0].LastName ;
              tUser.Email = res[0].Email;
              this._impUser = tUser;
              // this.trgIssueForm.get('RequesterName').setValue(this._impUser.RequesterName);
              console.log('TrgIssueComponent->ngOnInit- getWWIDDataByWWID -> this._impUser', this._impUser);
              // this.trgIssueForm.get('RequesterWWID').setValue(this._impUser.RequesterName);
            } else {
              this._impUser = null;
              this.trgIssueForm.get('RequesterWWID').setErrors({
                'required': true });
            }
        });
      }
    });
  }
  setImpUserToDefault() {
    const tUser: IImpUser = <IImpUser>{};
    tUser.WWID = this._requestService._userProfile.WWID;
    tUser.RequesterName = this._requestService._userProfile.DisplayName;
    tUser.Email = this._requestService._userProfile.Email;
    this._impUser = tUser;
  }
onReqActionChange(action: String) {
  console.log('TrgIssueComponent -> onReqActionChange: action', action);
  if (action && action.toLowerCase() === 'whytrg') {
    this.trgIssueForm.get('Screenshot').setValidators([]);
    this.trgIssueForm.get('Screenshot').updateValueAndValidity();
    this._hideScreenshot = true;
  } else if (action && action.toLowerCase() === 'trainingissue') {
    this.trgIssueForm.get('Screenshot').setValidators([FileValidator.validate]);
    this.trgIssueForm.get('Screenshot').updateValueAndValidity();
    this._hideScreenshot = false;
  }
}

  // (change)="onChangeMyRequest($event.target.checked)"
  onChangeMyRequest(isChecked: boolean): void {
    console.log('TrgIssueComponent -> onChangeMyRequest: _impUser', isChecked, this._impUser);
    if ( isChecked ) {
      // Set ImpUser to default
      this.setImpUserToDefault();
      this.trgIssueForm.get('RequesterWWID').setValue(this._impUser.WWID, {emitEvent: false});
      this.trgIssueForm.get('RequesterWWID').disable();
    } else {
      this.trgIssueForm.get('RequesterWWID').enable();
      this._impUser = null;
    }

  }
  saveRequest(): void {
    console.log('TrgIssueComponent -> saveRequest -');
    if (this.trgIssueForm.dirty && this.trgIssueForm.valid) {
        // Copy the form values over the product object values
        const p = Object.assign({}, this.trgIssueForm.value);
        // get selected trainng detail
        this.selTraining = this._requestService._trgUgInv.filter(trg =>
          trg.TrainingCode.toLowerCase().indexOf(p.Training.toLowerCase()) === 0)[0];
          console.log('TrgIssueComponent -> saveRequest-> this.selTraining', this.selTraining);
        p['TrainingName'] = this.selTraining.TrainingName;
        p['TrainingCode'] = this.selTraining.TrainingCode;
        p['Title'] = this._requestService._selReq.Title + ' - ' + p['ReqActSelect'];
        p['ReqSupportMailbox'] = this._requestService._selReq.ReqSupportMailbox;
        p['RequesterWWID'] = this._impUser.WWID;
        p['RequesterName'] = this._impUser.RequesterName;
        p['RequesterEmail'] = this._impUser.Email;
        p['ReqContentTypeId'] = this._requestService._selReq.ReqContentTypeId;
        console.log('TrgIssueComponent -> saveRequest-> p', p);
        this._trgIssueService.saveRequest(p).subscribe(
          result => {
            console.log('TrgIssueComponent ->saveRequest- > result', result);
            this.trgIssueForm.reset();
            this.router.navigate(['/reqmgmt/confirm']);
        },
        error => {
          this.errorMessage = error;
          console.log('TrgIssueComponent ->saveRequest- > error', error);
        }
      );
    }
}
cancelRequest(): void {
  this.router.navigate(['/home']);
}
  /*ngAfterViewInit(): void {
    // Watch for the blur event from any input element on the form.
    const controlBlurs: Observable<any>[] = this.formInputElements
        .map((formControl: ElementRef) => Observable.fromEvent(formControl.nativeElement, 'blur'));

    // Merge the blur event observable with the valueChanges observable
    Observable.merge(this.trgIssueForm.valueChanges, ...controlBlurs).debounceTime(800).subscribe(value => {
        this.displayMessage = this.genericValidator.processMessages(this.trgIssueForm);
    });
  }*/
}

TS Services
import {Injectable, OnInit} from '@angular/core';
import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/of';
import { sp, Web } from "@pnp/sp";
import { environment } from '../../../environments/environment';
import { RequestService } from 'app/core';
import { Response } from '@angular/http';
import { fromPromise } from 'rxjs/observable/fromPromise';

@Injectable()
export class TrgIssueService {
    constructor(private _reqService: RequestService) {
    }
    // public _reqTypes;
    saveRequest(req): Observable<any> {
        console.log('TrgIssueService -> saveRequest->req', req);
        if (!req.ID) {
            return this.createItem(req);
        }
        // return this.updateRequest(reqWhyTrg);
    }
    private createItem(_req):  Observable<any> {
        console.log('TrgIssueService -> createRequest->_req', _req);
        let _result = null;
        return fromPromise(sp.web.lists.getByTitle('Requests').items.add({
            Title: _req.Title,
            Action: _req.ReqActSelect,
            TrainingCode: _req.Training,
            TrainingName: _req.TrainingName,
            ReqSupportMailbox: _req.ReqSupportMailbox,
            ContentTypeId: _req.ReqContentTypeId,
            RequestDescription: _req.RequestDescription,
            RequesterName: _req.RequesterName,
            RequesterEmail: _req.RequesterEmail,
            RequesterWWID: _req.RequesterWWID,
        }).then((iar: any) => {
            console.log('TrgIssueService -> createItem-> iar', iar);
            if (_req.Screenshot[0]) {
            return sp.web.lists.getByTitle('Requests').items.getById(iar.data.ID).
                attachmentFiles.add(_req.Screenshot[0].name, _req.Screenshot[0]).then(file => {
                    _result = file;
                    return _result;
                });
            } else {
                //return iar;
            }
        }));
    }
    private updateRequest(_req) {
        let _result = null;
        sp.web.lists.getByTitle('Requests').items.add({
            Title: _req.AssignedTrg + ' - ' + _req.RequesterName,
            Training: _req.AssignedTrg,
            RequestDescription: _req.RequestDescription,
            RequesterName: _req.RequesterName,
            RequesterEmail: _req.RequestrEmail
        }).then((iar: any) => {
            console.log('TrgIssueService -> cre qateRequest-> iar', iar);
            _result = iar;
        });
    }
    private extractData(response: Response) {
        const body = response.json();
        return body.data || {};
    }
    private handleError(error: Response): Observable<any> {
        // in a real world app, we may send the server to some remote logging infrastructure
        // instead of just logging it to the console
        console.error(error);
        return Observable.throw(error.json().error || 'Server error');
    }
}

Thanks for your help.
Join the community to see this answer!
Join our exclusive community to see this answer & millions of others.
Unlock 1 Answer and 5 Comments.
Join the Community
Learn from the best

Network and collaborate with thousands of CTOs, CISOs, and IT Pros rooting for you and your success.

Andrew Hancock - VMware vExpert
See if this solution works for you by signing up for a 7 day free trial.
Unlock 1 Answer and 5 Comments.
Try for 7 days

”The time we save is the biggest benefit of E-E to our team. What could take multiple guys 2 hours or more each to find is accessed in around 15 minutes on Experts Exchange.

-Mike Kapnisakis, Warner Bros