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;

}
  • 1
    can you change it to .then ((response: any)=>{ console.log(response) let listItemCollection = response.map(item=>new ClassListItems(item)); and check ? – Gautam Sheth Oct 31 '18 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 – chris rowles Oct 31 '18 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; } – Gautam Sheth Oct 31 '18 at 14:17
  • I have updated the interface but still can't get the description - have tried URL.desc as well as URL.description – chris rowles Oct 31 '18 at 14:31
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;

  }
  • I have updated the interface but still can't get the description - have tried URL.desc as well as URL.description – chris rowles Oct 31 '18 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 – Gautam Sheth Oct 31 '18 at 15:28
  • 1
    You will have to change the html to item.URL and item.Desc respectively in the anchor tag – Gautam Sheth Oct 31 '18 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? – chris rowles Oct 31 '18 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 ! – Gautam Sheth Oct 31 '18 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 acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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