0

I have a React SPFx web part which will display specific columns in a Document Library. Would it be possible to have a property (say columnsToShow) that could define which columns to show? Say if it was comma delimited and looked like this "Title,Description" then it would only show those two columns?

I don't know a way to modify the Interface "IListItems" that I have below or if it's even possible?

Thanks P

    import * as React from 'react';  
import { css, DetailsList, IColumn, DetailsListLayoutMode as LayoutMode, ConstrainMode, CheckboxVisibility, SelectionMode, Link } from 'office-ui-fabric-react';  
import styles from './Splistitemsdata.module.scss';  
import { ISplistitemsdataProps } from './ISplistitemsdataProps';  
import * as jquery from 'jquery'; 

export interface IListItems{
  items:[  
        {  
           "HL":{
             Description:string;
             Url:string;
           }
          "Title":string,  
          "Id":string,  
          "Created":string;  
        }]  
}


export default class Splistitems extends React.Component<ISplistitemsdataProps, IListItems> {  

  private _columns: IColumn[];

  public constructor(props: ISplistitemsdataProps, state: IListItems){  
    super(props);  
    this.state = {  
      items: [  
        {  
          "HL":{
            "Description":"",
            "Url":""
          },  
          "Title": "",  
          "Id": "",  
          "Created":"",  
        }  
      ]  
    };  

    this._columns = [
      { key: 'Title', name: 'Title', fieldName: 'Title', minWidth: 100, maxWidth: 200, isResizable: true, data: 'string' },
      { key: 'Created', name: 'Created', fieldName: 'Created', minWidth: 100, maxWidth: 200, isResizable: true, data: 'string' },
    ];

    let columnData = {} as IColumn;
    columnData.key = "HL";
    columnData.name = "HL";
    columnData.fieldName = "HL";
    columnData.isResizable = true;
    columnData.data = "string";

    this._columns.push(columnData);

  }  
  
  public componentDidMount(){  
    var reactHandler = this;  
    jquery.ajax({  
        url: `${this.props.siteURL}/_api/web/lists/getbytitle('` + this.props.listName + `')/items`,  
        type: "GET",  
        headers:{'Accept': 'application/json; odata=verbose;'},  
        success: function(resultData) {  
          reactHandler.setState({  
            items: resultData.d.results  
          });  
        },  
        error : function(jqXHR, textStatus, errorThrown) {  
        }  
    });  
  }  

  
  
  
  
  
  public render(): React.ReactElement<ISplistitemsdataProps> {  

      const onRenderItemColumn = (item: any, index: number, column: IColumn) => {

      const fieldContent = item[column.fieldName as keyof IListItems] as any;

      let typeOfThisObject: string = (typeof fieldContent).toString();
      let valueToReturn: string = "";

      let theURL: string = "";
      let theDescription: string = "";

      if(typeOfThisObject == "object")
      {

        try{

          const values = Object.keys(fieldContent).map(key => fieldContent[key]);
          valueToReturn = "<a href='" + values[2] + "'>" + values[1] + "</a>";

          theURL = this.state.items[index].HL.Url;
          theDescription = this.state.items[index].HL.Description;

        }catch (e)          
        {
          valueToReturn = e.message.toString();
        }

      }else{
        valueToReturn = "no:" + fieldContent;
      }



      switch(column.key) {
        case 'Title':
        return(
          <span>{valueToReturn}</span>
        )
        case 'Created':
        return(
          <span>{fieldContent != null ? fieldContent.toString() : null}</span>
        )
        case 'HL' :
        return(
          <Link href={theURL}>{theDescription}</Link>
        );
        }

    };

    return (  
      // <div className={styles.listItemsForm}>  
      //   <div className={styles.Table}>  
      //     <div className={styles.Heading}>  
      //       <div className={styles.Cell}>Title</div>  
      //       <div className={styles.Cell}>Created</div>  
      //       <div className={styles.Cell}>Author</div>  
                  
      //     </div>  
      //       {this.state.items.map(function(item,key){  
      //         return (<div className={styles.Row} key={key}>  
      //             <div className={styles.Cell}>{item.Title}</div>  
      //             <div className={styles.Cell}>{item.Created}</div>  
      //             <div className={styles.Cell}>{item.Author.Title}</div>  
      //             <div className={styles.Cell}>{item.HL.Description} - {item.HL.URL}</div>  
      //           </div>);  
      //       })}  
                  
      //   </div>  
      // </div>  

      
        
      <DetailsList 
        selectionMode={SelectionMode.none}
        items={this.state.items} 
        columns={this._columns}
        isHeaderVisible = {true}
        layoutMode = {LayoutMode.justified}
        constrainMode ={ConstrainMode.unconstrained}
        checkboxVisibility={CheckboxVisibility.hidden} 
        onRenderItemColumn={onRenderItemColumn}      
      />

    );  

    

  }  
}  

1 Answer 1

0

It looks to me like the this._columns array is what's defining which columns are showing in the details list, because that's what's getting passed to the DetailsList component as its columns prop.

In order to make that configurable, you should look into implementing a property pane:

Make your SharePoint client-side web part configurable

You could have a text box there where you entered in the comma separated list of column names, or if you have a known quantity of specific columns to choose from, you could do some other type of controls, like a list of checkboxes or something.

Then you might want to move that _columns array from being an instance property to maybe being part of state, so that when someone updates the property pane with new selections, you can update that part of state and cause the DetailsList to re-render with the new columns array.

In order to add that to state you would have to add that structure to the IListItems interface (which will now be poorly named, since it really is an iterface for your web part's state which would now include an array of columns to show, not just an array of SharePoint list items).

Based on how you have this_columns set up in the constructor there, and looking at those objects you're setting up and their properties, it looks to me like to set that up in in your interface for your state, you would have to redefine IListItems as:

export interface IListItems {
    items: [
        {
            "HL": {
                Description: string;
                Url: string;
            }
            "Title": string,
            "Id": string,
            "Created": string;
        }
    ],
    columns: [
        {
            "key": string;
            "name": string;
            "fieldName": string;
            "minWidth": number;
            "maxWidth": number;
            "isResizable": boolean;
            "data": string;
        },
    ]
}

BUT don't take that as tested, vetted code... I've done very little actual TypeScript development, so that's just a guess...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.