Pnpjs: Updating Site Column Choice Fields

Created on 9 Oct 2018  路  8Comments  路  Source: pnp/pnpjs

Category

  • [ ] Enhancement
  • [ ] Bug
  • [ #] Question
  • [ ] Documentation gap/issue

Hope this is a quick question, I'm trying to update the choices field for an existing site column. But for some reason the Choices field parameter is complaining (red line underneath). What am i doing wrong? My arrayChoices is an array string. It seems to be wanting a

await web.fields.getByInternalNameOrTitle(internalName.innerText)
.update({
Description: validateTADesc,
Choices: arrayChoices
})

I tried using a comma separated string but that generated error: "The property 'Choices' does not exist on type 'SP.Field'. Make sure to only use property names that are defined by the type."
I can't see it in the reference guide either.

What the parameter for the update choice?

Thanks in advance

code answered question

Most helpful comment

Hi @Mike-tech,

Can you try using this approach?

sp.web.lists.getByTitle('Custom').fields.getByInternalNameOrTitle('ChoiceField')
  .update({
      Choices: {
          results: [ 'Choice 1', 'Choice 2' ]
      } as any // the workaround, this should be probably improved in the library to accept the correct payload
  }, 'SP.FieldChoice')
  .then(console.log)

All 8 comments

Hi @Mike-tech,

Can you try using this approach?

sp.web.lists.getByTitle('Custom').fields.getByInternalNameOrTitle('ChoiceField')
  .update({
      Choices: {
          results: [ 'Choice 1', 'Choice 2' ]
      } as any // the workaround, this should be probably improved in the library to accept the correct payload
  }, 'SP.FieldChoice')
  .then(console.log)

Great! The workaround works sweet.

As ever, you always on point. thanks @koltyakov

Sorry to re open this, while i can update the site column without any problem, the changes are not reflected on the associated columns being used in lists. If i manually update, the changes are reflected in associated columns.

Is there a parameter that's meant to be set to update all associated site columns?

@Mike-tech that's because, by design, the list takes a copy of the Content Types and the Site Columns used.
So you would need to something in PowerShell , or something similar to "manually copy" the site column to where it's being used.
BUT we can't remove the field in the list, and add a new one. That will remove all of the values in the items of the list.

If you instead replace the SchemaXML of the list field with the updated site column field, you should be good. Something like this in PowerShell with the PnP PowerShell cmdlets

# Connect to your site and tenant, log in via UI
Connect-PnPOnline https://<tenant>.sharepoint.com/sites/<site>/

# Get the Site Column
$Field = Get-PnPField "<NameOfField>"

# Get All Lists
$Lists = Get-PnPList

# Filter the list where the Site Column is being used
$FiltLsts = $Lists.where({(Get-PnPProperty -ClientObject $_ -Property "Fields").where({$_.Id -eq
$Field.Id  })})

# Csom context
$Context = Get-PnPContext

# Load the fields
foreach($List in $FiltLsts) {
$Context.Load($list.Fields)
}

# Must execute so you can access the fields
$Context.ExecuteQuery()

# Change SchemaXml with the new Site Column
foreach($List in $FiltLsts) {
$tempField = $list.Fields.GetById($Field.Id)
$tempField.SchemaXml = $Field.SchemaXml

# You must make these updates before last ExecuteQuery
$tempField.Update()
$list.Update()
}
$Context.ExecuteQuery()

Let me know if it helped!

@Mike-tech you could do a similar thing with PNPJs I realize, based on what @koltyakov wrote earlier.
Don't know if it's the best way of doing it, but it's one way at least.

// Get Site Column
const field = await sp.web.fields.getByInternalNameOrTitle('<Site Column>').get();

// All Lists, expand fields so we don't have to make so many calls later to get the fields
const lists = await sp.web.lists.expand('Fields').get();

// Filter lists where Site Column is in use
const filtLists = lists.filter(list => (
        list.Fields.filter(f => (f.Id === field.Id)).length > 0
));

// await doesn't work in forEach, so for it is
for (const list of filtLists) {
        // Update field in list with choices from the site column
        const updated = await sp.web.lists.getById(list.Id).fields.getById(field.Id).update({
            Choices: {
          results: field.Choices
      } as any 
        }, 'SP.FieldChoice');
        console.log(updated);
    } 

@simonagren my question was pertaining to @pnp js. I am aware this can be done via powershell/csom.

I initially tried a similar approach to your above code of getting all lists and filtering the fields, but i just didn't want to do multiple update on the list from the client where i have to worry about error occurring in the middle of the update and so forth.

I wanted a CSOM solution where you just call UpdateAndPushChanges and everything is updated via the server. In the end i opt for this solution via Azure function.

I will close this call, but if @koltyakov or any of his colleague can confirm if there is such an option or the best approach from the client side that is supported via @pnp js then please let the community know here.

@Mike-tech glad you found a way 馃榿.
There is no way to propagate the changes. You need to update the copies of the fields.

But did you see my second entry?
I would say that code is via PNPJs though, isn't it?
Maybe I'm misunderstanding you.

@simonagren yes that code is PnP. While you expanding Fields, it still requires multiple calls I didn't want for the context of my current work. I know I could batch these calls.

As I said before I was doing something very similar but was wondering if there is a method or a param that does all that work for us.

I just want an official clarity that updating associated fields individually is the only way.

Thanks for your input

Was this page helpful?
0 / 5 - 0 ratings