1
1
/* eslint-disable @microsoft/spfx/no-async-await */
2
2
import { SPHttpClient } from "@microsoft/sp-http" ;
3
- import { sp } from "@pnp/sp/presets/all" ;
3
+ import { IRenderListDataAsStreamResult , sp } from "@pnp/sp/presets/all" ;
4
4
import * as strings from "ControlStrings" ;
5
5
import {
6
6
DefaultButton ,
@@ -10,7 +10,7 @@ import { IDropdownOption } from "office-ui-fabric-react/lib/components/Dropdown"
10
10
import { ProgressIndicator } from "office-ui-fabric-react/lib/ProgressIndicator" ;
11
11
import { IStackTokens , Stack } from "office-ui-fabric-react/lib/Stack" ;
12
12
import * as React from "react" ;
13
- import { IUploadImageResult } from "../../common/SPEntities" ;
13
+ import { ISPField , IUploadImageResult } from "../../common/SPEntities" ;
14
14
import SPservice from "../../services/SPService" ;
15
15
import { IFilePickerResult } from "../filePicker" ;
16
16
import { DynamicField } from "./dynamicField" ;
@@ -69,6 +69,8 @@ export class DynamicForm extends React.Component<
69
69
// Initialize state
70
70
this . state = {
71
71
fieldCollection : [ ] ,
72
+ validationFormulas : { } ,
73
+ clientValidationFormulas : { } ,
72
74
isValidationErrorDialogOpen : false ,
73
75
} ;
74
76
// Get SPService Factory
@@ -81,7 +83,7 @@ export class DynamicForm extends React.Component<
81
83
* Lifecycle hook when component is mounted
82
84
*/
83
85
public componentDidMount ( ) : void {
84
- this . getFieldInformations ( )
86
+ this . getListInformation ( )
85
87
. then ( ( ) => {
86
88
/* no-op; */
87
89
} )
@@ -463,6 +465,277 @@ export class DynamicForm extends React.Component<
463
465
} ) ;
464
466
} ;
465
467
468
+ private getListInformation = async ( ) : Promise < void > => {
469
+ const {
470
+ listId,
471
+ listItemId,
472
+ disabledFields,
473
+ respectETag,
474
+ onListItemLoaded,
475
+ } = this . props ;
476
+ let contentTypeId = this . props . contentTypeId ;
477
+ let contentTypeName : string ;
478
+ try {
479
+ const listInfo = await this . _spService . getListFormRenderInfo ( listId ) ;
480
+ const additionalInfo = await this . _spService . getAdditionalListFormFieldInfo ( listId ) ;
481
+
482
+ const numberFields = additionalInfo . filter ( ( f ) => f . TypeAsString === "Number" || f . TypeAsString === "Currency" ) ;
483
+ const validationFormulas : Record < string , Pick < ISPField , "ValidationFormula" | "ValidationMessage" > > = additionalInfo . reduce ( ( prev , cur ) => {
484
+ if ( ! prev [ cur . InternalName ] && cur . ValidationFormula ) {
485
+ prev [ cur . InternalName ] = {
486
+ ValidationFormula : cur . ValidationFormula ,
487
+ ValidationMessage : cur . ValidationMessage ,
488
+ } ;
489
+ }
490
+ return prev ;
491
+ } , { } ) ;
492
+
493
+ const spList = sp . web . lists . getById ( listId ) ;
494
+ let item = null ;
495
+ let etag : string | undefined = undefined ;
496
+ if ( listItemId !== undefined && listItemId !== null && listItemId !== 0 ) {
497
+ item = await spList . items . getById ( listItemId ) . get ( ) ;
498
+
499
+ if ( onListItemLoaded ) {
500
+ await onListItemLoaded ( item ) ;
501
+ }
502
+
503
+ if ( respectETag !== false ) {
504
+ etag = item [ "odata.etag" ] ;
505
+ }
506
+ }
507
+
508
+ if ( contentTypeId === undefined || contentTypeId === "" ) {
509
+ contentTypeId = Object . keys ( listInfo . ContentTypeIdToNameMap ) [ 0 ] ;
510
+ }
511
+ contentTypeName = listInfo . ContentTypeIdToNameMap [ contentTypeId ] ;
512
+
513
+ const clientValidationFormulas = listInfo . ClientForms . Edit [ contentTypeName ] . reduce ( ( prev , cur ) => {
514
+ if ( cur . ClientValidationFormula ) {
515
+ prev [ cur . InternalName ] = {
516
+ ValidationFormula : cur . ClientValidationFormula ,
517
+ ValidationMessage : cur . ClientValidationMessage ,
518
+ } ;
519
+ }
520
+ return prev ;
521
+ } , { } as Record < string , Pick < ISPField , "ValidationFormula" | "ValidationMessage" > > ) ;
522
+
523
+ const tempFields : IDynamicFieldProps [ ] = [ ] ;
524
+ let order : number = 0 ;
525
+ const hiddenFields =
526
+ this . props . hiddenFields !== undefined ? this . props . hiddenFields : [ ] ;
527
+ let defaultDayOfWeek : number = 0 ;
528
+
529
+ for ( let i = 0 , len = listInfo . ClientForms . Edit [ contentTypeName ] . length ; i < len ; i ++ ) {
530
+ const field = listInfo . ClientForms . Edit [ contentTypeName ] [ i ] ;
531
+
532
+ // Handle only fields that are not marked as hidden
533
+ if ( hiddenFields . indexOf ( field . InternalName ) < 0 ) {
534
+ order ++ ;
535
+ let hiddenName = "" ;
536
+ let termSetId = "" ;
537
+ let anchorId = "" ;
538
+ let lookupListId = "" ;
539
+ let lookupField = "" ;
540
+ const choices : IDropdownOption [ ] = [ ] ;
541
+ let defaultValue = null ;
542
+ const selectedTags : any = [ ] ; // eslint-disable-line @typescript-eslint/no-explicit-any
543
+ let richText = false ;
544
+ let dateFormat : DateFormat | undefined ;
545
+ let principalType = "" ;
546
+ let minValue : number | undefined ;
547
+ let maxValue : number | undefined ;
548
+ let showAsPercentage : boolean | undefined ;
549
+ if ( item !== null ) {
550
+ defaultValue = item [ field . InternalName ] ;
551
+ } else {
552
+ defaultValue = field . DefaultValue ;
553
+ }
554
+
555
+ if ( field . FieldType === "Choice" || field . FieldType === "MultiChoice" ) {
556
+ field . Choices . forEach ( ( element ) => {
557
+ choices . push ( { key : element , text : element } ) ;
558
+ } ) ;
559
+ } else if ( field . FieldType === "Note" ) {
560
+ richText = field . RichText ;
561
+ } else if ( field . FieldType === "Number" || field . FieldType === "Currency" ) {
562
+ const numberField = numberFields . find ( f => f . InternalName === field . InternalName ) ;
563
+ if ( numberField ) {
564
+ minValue = numberField . MinimumValue ;
565
+ maxValue = numberField . MaximumValue ;
566
+ }
567
+ showAsPercentage = field . ShowAsPercentage ;
568
+ } else if ( field . FieldType === "Lookup" || field . FieldType === "MultiLookup" ) {
569
+ lookupListId = field . LookupListId ;
570
+ lookupField = field . LookupFieldName ;
571
+ if ( item !== null ) {
572
+ defaultValue = await this . _spService . getLookupValues (
573
+ listId ,
574
+ listItemId ,
575
+ field . InternalName ,
576
+ lookupField ,
577
+ this . webURL
578
+ ) ;
579
+ } else {
580
+ defaultValue = [ ] ;
581
+ }
582
+ } else if ( field . FieldType === "TaxonomyFieldTypeMulti" ) {
583
+ hiddenName = field . HiddenListInternalName ;
584
+ termSetId = field . TermSetId ;
585
+ anchorId = field . AnchorId ;
586
+ if ( item !== null ) {
587
+ item [ field . InternalName ] . forEach ( ( element ) => {
588
+ selectedTags . push ( {
589
+ key : element . TermGuid ,
590
+ name : element . Label ,
591
+ } ) ;
592
+ } ) ;
593
+
594
+ defaultValue = selectedTags ;
595
+ } else {
596
+ if ( defaultValue !== null && defaultValue !== "" ) {
597
+ defaultValue . split ( / # | ; / ) . forEach ( ( element ) => {
598
+ if ( element . indexOf ( "|" ) !== - 1 )
599
+ selectedTags . push ( {
600
+ key : element . split ( "|" ) [ 1 ] ,
601
+ name : element . split ( "|" ) [ 0 ] ,
602
+ } ) ;
603
+ } ) ;
604
+
605
+ defaultValue = selectedTags ;
606
+ }
607
+ }
608
+ if ( defaultValue === "" ) defaultValue = null ;
609
+ } else if ( field . FieldType === "TaxonomyFieldType" ) {
610
+ termSetId = field . TermSetId ;
611
+ anchorId = field . AnchorId ;
612
+ if ( item !== null ) {
613
+ const response =
614
+ await this . _spService . getSingleManagedMetadataLabel (
615
+ listId ,
616
+ listItemId ,
617
+ field . InternalName
618
+ ) ;
619
+ if ( response ) {
620
+ selectedTags . push ( {
621
+ key : response . TermID ,
622
+ name : response . Label ,
623
+ } ) ;
624
+ defaultValue = selectedTags ;
625
+ }
626
+ } else {
627
+ if ( defaultValue !== "" ) {
628
+ selectedTags . push ( {
629
+ key : defaultValue . split ( "|" ) [ 1 ] ,
630
+ name : defaultValue . split ( "|" ) [ 0 ] . split ( "#" ) [ 1 ] ,
631
+ } ) ;
632
+ defaultValue = selectedTags ;
633
+ }
634
+ }
635
+ if ( defaultValue === "" ) defaultValue = null ;
636
+ } else if ( field . FieldType === "DateTime" ) {
637
+ if ( item !== null && item [ field . InternalName ] ) {
638
+ defaultValue = new Date ( item [ field . InternalName ] ) ;
639
+ } else if ( defaultValue === "[today]" ) {
640
+ defaultValue = new Date ( ) ;
641
+ }
642
+
643
+ dateFormat = field . DateFormat || "DateOnly" ;
644
+ defaultDayOfWeek = ( await this . _spService . getRegionalWebSettings ( ) ) . FirstDayOfWeek ;
645
+ } else if ( field . FieldType === "UserMulti" ) {
646
+ if ( item !== null ) {
647
+ defaultValue = this . _spService . getUsersUPNFromFieldValue (
648
+ listId ,
649
+ listItemId ,
650
+ field . InternalName ,
651
+ this . webURL
652
+ ) ;
653
+ } else {
654
+ defaultValue = [ ] ;
655
+ }
656
+ principalType = field . PrincipalAccountType ;
657
+ } else if ( field . FieldType === "Thumbnail" ) {
658
+ if ( defaultValue ) {
659
+ defaultValue = JSON . parse ( defaultValue ) . serverRelativeUrl ;
660
+ }
661
+ } else if ( field . FieldType === "User" ) {
662
+ if ( item !== null ) {
663
+ const userEmails : string [ ] = [ ] ;
664
+ userEmails . push (
665
+ ( await this . _spService . getUserUPNFromFieldValue (
666
+ listId ,
667
+ listItemId ,
668
+ field . InternalName ,
669
+ this . webURL
670
+ ) ) + ""
671
+ ) ;
672
+ defaultValue = userEmails ;
673
+ } else {
674
+ defaultValue = [ ] ;
675
+ }
676
+ principalType = field . PrincipalAccountType ;
677
+ } else if ( field . FieldType === "Location" ) {
678
+ defaultValue = JSON . parse ( defaultValue ) ;
679
+ } else if ( field . FieldType === "Boolean" ) {
680
+ defaultValue = Boolean ( Number ( defaultValue ) ) ;
681
+ }
682
+
683
+ tempFields . push ( {
684
+ newValue : null ,
685
+ fieldTermSetId : termSetId ,
686
+ fieldAnchorId : anchorId ,
687
+ options : choices ,
688
+ lookupListID : lookupListId ,
689
+ lookupField : lookupField ,
690
+ changedValue : defaultValue ,
691
+ fieldType : field . FieldType ,
692
+ fieldTitle : field . Title ,
693
+ fieldDefaultValue : defaultValue ,
694
+ context : this . props . context ,
695
+ disabled :
696
+ this . props . disabled ||
697
+ ( disabledFields &&
698
+ disabledFields . indexOf ( field . InternalName ) > - 1 ) ,
699
+ listId : this . props . listId ,
700
+ columnInternalName : field . InternalName ,
701
+ label : field . Title ,
702
+ onChanged : this . onChange ,
703
+ required : field . Required ,
704
+ hiddenFieldName : hiddenName ,
705
+ Order : order ,
706
+ isRichText : richText ,
707
+ dateFormat : dateFormat ,
708
+ firstDayOfWeek : defaultDayOfWeek ,
709
+ listItemId : listItemId ,
710
+ principalType : principalType ,
711
+ description : field . Description ,
712
+ minimumValue : minValue ,
713
+ maximumValue : maxValue ,
714
+ showAsPercentage : showAsPercentage ,
715
+ } ) ;
716
+
717
+ // This may not be necessary now using RenderListDataAsStream
718
+ tempFields . sort ( ( a , b ) => a . Order - b . Order ) ;
719
+ }
720
+ }
721
+
722
+ // Do formatting and validation parsing here
723
+ console . log ( 'Validation Formulas' , validationFormulas ) ;
724
+ console . log ( 'Client Side Validation Formulas' , clientValidationFormulas ) ;
725
+
726
+ this . setState ( {
727
+ clientValidationFormulas,
728
+ fieldCollection : tempFields ,
729
+ validationFormulas,
730
+ etag
731
+ } ) ;
732
+
733
+ } catch ( error ) {
734
+ console . log ( `Error get field informations` , error ) ;
735
+ return null ;
736
+ }
737
+ }
738
+
466
739
//getting all the fields information as part of get ready process
467
740
private getFieldInformations = async ( ) : Promise < void > => {
468
741
const {
0 commit comments