Pnpjs: Image Upload Metatadata update fails. Incorrect item ID found

Created on 2 Jul 2019  路  9Comments  路  Source: pnp/pnpjs

Category

  • [ ] Bug

Version

Please specify what version of the library you are using: [ V3.0.10 ]

Please specify what version(s) of SharePoint you are targeting: [ 2019 ]

Approach One:

newweb.getFolderByServerRelativeUrl("/ImageGallery/").files.add(fileName, newfile, true) .then(function (filedata) { newweb.lists.getByTitle("ImageGallery").items.select("ID,FileLeafRef").filter("FileLeafRef eq '"+fileName+"'").get() .then(function(results){ newweb.lists.getByTitle("ImageGallery").items.getById(results[0].ID).update(AlbumData) .then(function(updatedResults){ $('.loader-overlay').addClass('loaded'); alertify.alert().setting({ 'label': 'OK', 'message': 'File Uploaded Successfully', 'onok': function () { window.location.href = _spPageContextInfo.webAbsoluteUrl + "/Pages/ViewAllAlbum.aspx"; } }).show().setHeader('<em>Confirmation</em> ').set('closable', false); }) .catch(function (err) { // ErrorLogger(err.message, "ImageGallery", "ImageGallery"); }); }) .catch(function (err) { // ErrorLogger(err.message, "ImageGallery", "ImageGallery"); }); }) .catch(function (err) { // ErrorLogger(err.message, "ImageGallery", "ImageGallery"); });

Approach Two:

Followed the WA and again failed

https://github.com/SharePoint/PnP-JS-Core/issues/320#issuecomment-279964675

Approach Three :

https://github.com/SharePoint/PnP-JS-Core/issues/320#issuecomment-281392511

' ODataDefaultParser() is not defined ' error thrown

remember i cannot use typescript here so i can't do import or export as of my knowledge.

Approach Four:

Web.lists.getByTitle(listTitle).select('RootFolder/ServerRelativeUrl').expand('RootFolder').get().then(function(list) { Web.getFolderByServerRelativeUrl(list.RootFolder.ServerRelativeUrl).files.add(filename, blob, true) }).then(function(fileAddResult) { // fileAddResult -> item.Id fileAddResult.file.listItemAllFields.get().then(function(item) { item.Id; }); }).then(function(itemId) { // set metadata if (metadata) { Web.lists.getByTitle(listTitle).items.getById(itemId).update(metadata); } });

Expected / Desired Behavior / Question

I am using a content editor. This is not a SPFx web part so i cannot use TypeScript with PNP

I want to upload a Picture inside a Picture Library and i want to update the relevant metadata with 3-4 fields

Observed Behavior

I am have tried 3-4 approaches but all failed and having same problem.
What happens is due to the cache in browser the metadata update fails because incorrect ID goes and I get 404 item not found. This is very intermittent and causing trouble because not able to figure on what case as it happens random

Steps to Reproduce

  1. Add Image to the in library and update the relevant fields -> Success
  2. Delete the Image -> Success
  3. Add Image to the library -> Success
    | --> Update metadata -> Failed (because fetches previous ID) throws error ITEM not found 404

Please any help over here. AS this is a long pending one month issue for us.

code answered not a bug question

Most helpful comment

The URL above is a result of something else but not a sample below. As a date section is in the wrong format and in another place and another method. I don't want to turn the question to the general development topic and it's already become an offtopic for PnPjs-related things.

The answer still the same or paraphrased one and I have nothing to add. But ask you gently to validate code logic on your end.

we can't use async await because we need to support IE

Certainly CAN and even SHOULD. And should not use raw ES5 (this is a way to chaos) but TypeScript or ESNext with Flow/@ts-check at least, and linting and bundling and automated pipelines and code-based provisioning, nowadays it's a minimal requirement in SharePoint Development lands and outside SP as well. But all of these is a completely different topic. [Sorry, wasn't able to stop myself from writing this]

All 9 comments

It's not a bug but a behavior to take into consideration: "get requests with the same URL are cashed by browser". So if a file is deleted and another file with the same path is uploaded you should consider this in the app.

It's possible to provide a unique part of the URL with a query parameter to force not-cashed response, for instance using this approach:

import { sp } from '@pnp/sp';

(async () => {

  const folder = sp.web.getFolderByServerRelativeUrl('/sites/site/Shared Documents');
  const { file, data } = await folder.files.add('new-one.txt', 'data');
  const item = await file.getItem(`Id&_hash=${new Date().toISOString()}`); // force no-cashed response
  await item.update({ Title: new Date().toISOString() });

})().catch(console.warn);

I am using a content editor.

Sorry, it's not a justification not using TypeScript. =) If you in On-Prem/none SPFx world I'd recommend sppp, it includes PnPjs and all the required setup and pipelines.

Thanks Koltyakov,
I assume the problem should be with same file name which seems to be creating same path.
Will the below code work instead ?

`var newfile = input.files[0];
/// var fileName = ddlVideoAlbum + "-" + newfile.name;
var fileName = Math.random().toString(36).substr(2, 9) + ".png";
fileName = ddlVideoAlbum + "-" + fileName;

newweb.getFolderByServerRelativeUrl("/ImageGallery/").files.add(fileName, newfile, true).then(function (filedata) {
    filedata.file.listItemAllFields.get().then(function(listItemAllFields){
            newweb.lists.getByTitle("ImageGallery").items.getById(listItemAllFields.Id).update(AlbumData)
            .then(function(results){
                $('.loader-overlay').addClass('loaded');
                alertify.alert().setting({
                    'label': 'OK',
                    'message': 'File Uploaded Successfully !',
                    'onok': function () {
                        window.location.href = _spPageContextInfo.webAbsoluteUrl + "/Pages/ViewAllAlbum.aspx";
                    }
                }).show().setHeader('<em>Confirmation</em> ').set('closable', false);
            })
        })
    })`

It works now. You are really great. I just used above code, randomized file name and found it to be working like charm.
Thanks for the biggie help..
Kudos.. 馃榿鉁岋笍

Reopening since after changing the file name randomly issue still persist.
Any other solution can be done for this ?

Current code which is used is

var newfile = input.files[i]; var fileName = Math.random().toString(36).substr(2, 9) + ".png"; fileName = ddlVideoAlbum + "-" + fileName; newweb.getFolderByServerRelativeUrl("/ImageGallery/").files.add(fileName, newfile, true).then(function (filedata) { filedata.file.listItemAllFields.get().then(function(listItemAllFields){ newweb.lists.getByTitle("ImageGallery").items.getById(listItemAllFields.Id).update(AlbumData) .then(function(results){ fileUploadCount ++; if(fileUploadCount === input.files.length){ $('.loader-overlay').addClass('loaded'); alertify.alert().setting({ 'label': 'OK', 'message': 'File Uploaded Successfully !', 'onok': function () { window.location.href = _spPageContextInfo.webAbsoluteUrl + "/Pages/ViewAllAlbum.aspx"; } }).show().setHeader('<em>Confirmation</em> ').set('closable', false); } }).catch(function(error){ console.log(error.message); $('.loader-overlay').addClass('loaded'); alertify.alert().setting({ 'label': 'OK', 'message': 'File Uploaded Successfully !', 'onok': function () { window.location.href = _spPageContextInfo.webAbsoluteUrl + "/Pages/ViewAllAlbum.aspx"; } }).show().setHeader('<em>Confirmation</em> ').set('closable', false); }) }) }) .catch(function (error) { // ErrorLogger(error.message, "ImageGallery", "ImageGallery") });

No offenses, it's a pain reading not formatted code samples. Please also try generalizing the code, nobody interested in reading chunks of not related jQuery-ish stuff. Please!

Regards the caching recommendation, you ignored it and did exactly the same what before and therefore ended up with the same cached result expectedly.

filedata.file.listItemAllFields.get() this line...

will end up sending GET request to:

https://tenant/sites/site/_api/web/getFolderByServerRelativeUrl('/sites/sites/lib/folder')/files('file-name.etx')/listItemAllFields

which, guess what? Cached.

My recommendation, while knowing that your app deals with the same file locations after a previous file is already deleted, was adding a unique part to the URL to be /sites/site/_api/web/getFolderByServerRelativeUrl('/sites/sites/lib/folder')/files('file-name.etx')/listItemAllFields?__hash=2019-07-03T06:13:01.674Z which won't be cached.

And the suggestion was getItem helper and file.getItem(`Id&_hash=${new Date().toISOString()}`).

With listItemAllFields, it's also possible - file.listItemAllFields.select(`Id&_hash=${new Date().toISOString()}`).get().

Apologies Koltyakov. Will ensure i will format the code from hereafter. Let me try retry with your solution.

Tried this, but still facing issue internal server error.
I would really appreciate if you can provide code snippet. Between we can't use async await because we need to support IE

m/_api/web/getFolderByServerRelativeUrl('/ImageGallery/')/files/add(overwrite=true,url='155-voxu4ia4y.pngWed%20Jul%2003%202019%2012:06:04%20GMT+0530%20(India%20Standard%20Time)')

Code
`

fileName = ddlVideoAlbum + "-" + fileName + n;

    newweb.getFolderByServerRelativeUrl("/ImageGallery/").files.add(fileName, newfile, true).then(function (filedata) {
        filedata.file.listItemAllFields.select(`Id&_hash=${new Date().toISOString()}`).get().then(function(listItemAllFields){
                newweb.lists.getByTitle("ImageGallery").items.getById(listItemAllFields.Id).update(AlbumData)

`

The URL above is a result of something else but not a sample below. As a date section is in the wrong format and in another place and another method. I don't want to turn the question to the general development topic and it's already become an offtopic for PnPjs-related things.

The answer still the same or paraphrased one and I have nothing to add. But ask you gently to validate code logic on your end.

we can't use async await because we need to support IE

Certainly CAN and even SHOULD. And should not use raw ES5 (this is a way to chaos) but TypeScript or ESNext with Flow/@ts-check at least, and linting and bundling and automated pipelines and code-based provisioning, nowadays it's a minimal requirement in SharePoint Development lands and outside SP as well. But all of these is a completely different topic. [Sorry, wasn't able to stop myself from writing this]

Going to close this as answered. Thanks @koltyakov

Was this page helpful?
0 / 5 - 0 ratings