0

I am trying to get items from a links list with managed metadata. I am getting an error 'response.map is not a function'. I have used the sample from this answer to get the data using RenderListDataAsStream (SPFX - cannot get actual label of managed metadata list field). I can get the data - I can see it in the console - so I know that the caml query works, but can't seem to map the results. I get the error 'response.map is not a function'.

There is my code:

import * as React from 'react';
import styles from './LinksWp.module.scss';
import { ILinksWpProps } from './ILinksWpProps';
import { escape } from '@microsoft/sp-lodash-subset';
import pnp from "sp-pnp-js";
import { ClassListItems } from './ClassListItem';
import { ISPListItem } from './IListItems';
import { sp, RenderListDataParameters, RenderListDataOptions } from '@pnp/sp';

export default class LinksWp extends React.Component<ILinksWpProps, any> {

public constructor(props:ILinksWpProps,any)
{
super(props);
this.state={
items:[]
}
}



  public render(): React.ReactElement<ILinksWpProps> {
    return (
      <div><h1>{this.props.description}</h1>
      <div>{this.state.items.map(function(item:ISPListItem){
      return(
      <div>
       <span><a href={item.URL.Url}>{item.URL.Description}</a></span>
      </div>
    )

})}</div>


      </div>

    );
  }

public componentDidMount(){

  this._getListItems();
}

private _getListItems():void

{


pnp.sp.web.lists.getByTitle('Quick Links').renderListDataAsStream({
  RenderOptions: RenderListDataOptions.ListData,
  ViewXml :  `<View><Query><Where><Eq><FieldRef Name='Function' />
  <Value Type='TaxonomyFieldTypeMulti'>Group IT</Value></Eq></Where></Query><ViewFields>
  <FieldRef Name='URLwMenu2' /><FieldRef Name='Region' />
  <FieldRef Name='Function' /><FieldRef Name='Geography' />
  </ViewFields><QueryOptions />
  </View>`
}).then
((response)=>{
  console.log(response)
   **let listItemCollection = response.map(item=>new ClassListItems(item));** // this is where I get the error
   this.setState({items: listItemCollection});
  }

)

}
}

I have defined an interface and a class for this as well

import { ISPListItem } from "./IListItems"

export class ClassListItems {

public URL;
public Region;
public Function;
public Geography;

constructor(item: ISPListItem) {

this.URL = item.URL;
this.Region = item.Region;
this.Function = item.Function;
this.Geography = item.Geography;

}
}

export interface ISPListItem{

URL;
Region : string;
Function : string;
Geography : string;

}
4
  • 1
    can you change it to .then ((response: any)=>{ console.log(response) let listItemCollection = response.map(item=>new ClassListItems(item)); and check ? Commented Oct 31, 2018 at 14:05
  • That worked so thanks so much. I am now having problems trying to get the value of the url description. The console window shows it to be 'URL.desc' but that's not returning anything. I can display the actual URL but not the description Commented Oct 31, 2018 at 14:16
  • 1
    in your interface, change the type of URL to any, i.e export interface ISPListItem{ URL: any; Region : string; Function : string; Geography : string; } Commented Oct 31, 2018 at 14:17
  • I have updated the interface but still can't get the description - have tried URL.desc as well as URL.description Commented Oct 31, 2018 at 14:31

2 Answers 2

1

As mentioned in comments, the data returned is in the form of a javascript object. Now, we can't use map function over an object, it will only work with arrays. That array is present as response.Row in the AJAX response.

So, modify your code as below and then use that to set the state:

//code omitted for brevity

}).then
((response: any)=>{
  console.log(response)
   let listItemCollection = response.Row.map(item=>new ClassListItems(item));
   this.setState({items: listItemCollection});
  }

)

To get URL description, you should modify the interfaces as below:

export interface ISPListItem {

  URL: any;  
  Desc: any;
  Region: string;
  Function: string;
  Geography: string;

}

export class ClassListItems {

  public URL: any;
  public Desc : string
  public Region: string;
  public Function: string;
  public Geography: string;

  constructor(item: ISPListItem) {

    this.URL = item.URL;
    this.Desc = item["URL.desc"];
    this.Region = item.Region;
    this.Function = item.Function;
    this.Geography = item.Geography;

  }
8
  • I have updated the interface but still can't get the description - have tried URL.desc as well as URL.description Commented Oct 31, 2018 at 14:40
  • 1
    Updated the code, please try and let me know. If it helped you fix the issue, you can accept it as answer by ticking the checkbox besides the answer like this Commented Oct 31, 2018 at 15:28
  • 1
    You will have to change the html to item.URL and item.Desc respectively in the anchor tag Commented Oct 31, 2018 at 15:34
  • Great that worked really well thanks! Great Job! One final thing to do is to display the managed metadata fields - I have tried adding the labels to the interface and class eg this.CFLabel = item.Function["0"].Label. This works well but obviously I am only getting the label by referencing the position of the item in an array - is there another way of doing this? Commented Oct 31, 2018 at 16:53
  • 1
    I think you need to create another property of type any or array and then iterate over, will require some trial and error ! Commented Oct 31, 2018 at 19:09
0

I worked out how to do the last bit - to display multi value managed metadata values. I created an additional interface and a class for a label

export interface ISPLabel{

    Label : any;
    TermID: any;


    }

export class ClassListItemLabels {

    public Label: any;
    public TermID: any;


    constructor(i: ISPLabel) {

    this.Label = i.Label;
    this.TermID = i.TermID;

    }
    }

The I can get the labels out mapping the labels to the interface and class. I think I can use .map() as the property is an array

     <div>{
         this.state.items.sort( (a, b) =>{ 
          return a.Desc == b.URL.Desc ? 0 : a.Desc < b.Desc ? -1 : 1;
        })


        .map(function(item:ISPListItem){
      return(
      <div>
        <ul className={styles.myUl}>
          <li className={styles.myUlLi}><a href={item.URL}>{item.Desc}</a></li> 

          <span><ul className={styles.ulLables}>{
            /*  Getting the Labels Out   */
            item.Function1

            .map(function(i:ISPLabel){
     return(
    <li>{i.Label}; </li>

     )
            }

            )
          }</ul></span>
        </ul>

      </div>
    )

})}</div>

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.