5

Im working on a pretty simple spfx CommandSet extension. Its goal is to duplicate an item, when an item is selected. I have the working code. My problem is, that i searched the context property, but could not find a method, to update the ListView, to show the newly created(duplicated) item. (By default it not shows the created item because i created it with an API call)

Code:

@override
public onListViewUpdated(event: IListViewCommandSetListViewUpdatedParameters): void {
  const duplicateCommand: Command = this.tryGetCommand('DUPLICATE_ITEM');
  if (duplicateCommand) {
    duplicateCommand.visible = (event.selectedRows.length === 1);
  }
}

@override
public onExecute(event: IListViewCommandSetExecuteEventParameters): void {
  switch (event.itemId) {
    case 'DUPLICATE_ITEM': this.DuplicateItem(event); break;
    default: throw new Error('Unknown command');
  }
}
private DuplicateItem(event: IListViewCommandSetExecuteEventParameters): void {
  //stuff to do
  pnp.sp.web.lists.getByTitle(listName).items.add(data)
    .then((result: any) => {
      //refresh ListView to show new item
    }).catch(error => {
      //error handling
    });
}

How can i do this?

6
+50

There is a Microsoft sample project on github that does exactly the same. Looking at their code, it does mention that there is currently no way to refresh just the list view and their solution seems to be reloading the entire page using location.reload();. If you look at the file SpfxCloneCommandSet.ts they mention that there is currently no way to reload just the list view and just refresh entire page.

1

Unfortunately, you cannot update a list view with the help of user API without refreshing the whole page. But it is possible to extract corresponding method from a built-in require module with the below code:

var listEl = document.querySelector('.sp-App-root');
var listVM = __ko.dataFor(listEl);
var ii = listVM.resources.consume(require.s.contexts._.defined.eR.itemInvalidator);
ii.invalidateCurrentItemSet();

Since the module containing the 'itemValidator' can be renamed in future updates of SharePoint, I optimized the above by iterating through all loaded modules and checking whether the 'itemInvalidator' property exists:

var modules = window.require.s.contexts._.defined;
for (var p in modules) {
    if (modules.hasOwnProperty(p) && modules[p] && modules[p].itemInvalidator) {
        var itemInvalidatorKey = modules[p].itemInvalidator;
        var rootEl = document.getElementById('appRoot');
        var rootVM = window.__ko.dataFor(rootEl);
        var itemInvalidator = rootVM.resources.consume(itemInvalidatorKey);
        itemInvalidator.invalidateCurrentItemSet()
        break;
    }
}
0

Please check out this workaround which is working for me:

 public static forceListViewUpdate() {

    try {
      let modules = (window as any).require.s.contexts._.defined;
      for (var p in modules) {
        if (modules.hasOwnProperty(p) && modules[p] && modules[p].itemInvalidator) {
          let itemInvalidatorKey = modules[p].itemInvalidator;
          let rootEl = document.getElementById('appRoot');
          let rootVM = (window as any).__ko.dataFor(rootEl);
          let itemInvalidator = rootVM.resources.consume(itemInvalidatorKey);
          itemInvalidator.invalidateCurrentItemSet();
          break;
        }
      }
    } catch (e) {
      console.log('Unable to update ListView:', e);
    }

      }

If you like, check the source here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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