Use async functions in List or Libary Control column templates

Hey There,

I'm using the pnp Libary alot, but this often results in problems, as the return value of asynchronous functions is a promise, not a value.

Here im trying to replace the value of a column with one i did some calculations to, this like I mentioned doens't work.

Could you help me find a workaround for this?

Best whishes form Germany
Nico

fd.control('table1').templates = {
    column1: function(ctx) {

        //returns a promise
        return (async () => {
            let results = await getPos(ctx.row.ID);
            /*doing stuff here*/
            return results;
        })();  
}}

function getPos(id) {
    return  pnp.sp.web.lists.getByTitle('positions').items
            .filter(`ID eq ${id}`)
            .get();
}

Hello @nI3o,

ITo replace the value of the column with the value from a different list using PnPjs library, first, you need to add unique ID to HTML tag and then start the request. Please see the code sample.

fd.control('SPDataTable1').templates = {
        
        Title: function(ctx) {
            var value = ctx.row.Title;
            var itemId = ctx.row.ID;

            if (!value) {
                return '';
            }
            //add tag with unique ID
            return '<span id="Title-' + ctx.row.ID + '">' + value + '</span>'
        }
    }
    
fd.control('SPDataTable1').widget.dataSource.data().forEach(function(item) {
        pnp.sp.web.lists.getByTitle("List").items.getById(item.ID).get().then(function(item){
        var tagID = item.ID
        return tagID
      }).then(function(tagID){
          var spanID = '#Title-' + tagID;
          $(spanID).html('new')
      })
})

@mnikitina Thanks for the solution, i finaly had to time finish the code.

One more question though: If a control has one then more page i have to rerun the function that replaces the values.

fd.control('').$on('change', function(){} 

Doens't react, is there some Vue listener that reacts to changing pages?

Greetings Nico

Here's one solution. If someone has a cleaner one, i'd like to know about it.

let pager_buttons = document.querySelectorAll(".SPDataTable .k-pager-nav")
for (const button of pager_buttons) {
  button.addEventListener('click', function(event) {
    console.log('Happy Holidays');
  })
}

Hello @nI3o,

Another option is to periodically call the function like this:

fd.spRendered(function() {
    fd.control('SPDataTable1').templates = {

            Title: function(ctx) {
                var value = ctx.row.Title;
                var itemId = ctx.row.ID;

                if (!value) {
                    return '';
                }
                //add tag with unique ID
                return '<span id="Title-' + ctx.row.ID + '">' + value + '</span>'
            }
        }
    setInterval(function(){

    fd.control('SPDataTable1').widget.dataSource.data().forEach(function(item) {
            pnp.sp.web.lists.getByTitle("List").items.getById(item.ID).get().then(function(item){
            var tagID = item.ID
            return tagID
          }).then(function(tagID){
              var spanID = '#Title-' + tagID;
              $(spanID).html(spanID)
          })
    })
    }, 2000);
});

@mnikitina That seems more stable, but im doing a pnp.get for each item on another quite large list.

I'm no expert, but that function takes almost a second to resolve, so i think in this case its better not to call it every two seconds?

@nI3o,

You can change the interval to 5/10 seconds and decide which one is optimal for you.