Add IDs for Files and Folders in iSheet XML

In file and folder link columns, and in file and folder metadata iSheets, in the XML feed, can the IDs of the files and folders be included?  Without the IDs it's very difficult to make any use of those columns (and corresponding iSheets).  It should be relatively simple to get that information and the XML is extensible and should support additional xml nodes or attributes with that information.  For example:  a column with a document currently looks like:

<column position="1" columnid="123"><rawData><document><docName><![CDATA[Agreement]]></docName><docExtension><![CDATA[pdf]]></docExtension><docIndex/></document></rawData><displayData><![CDATA[ Agreement

Just add <id>####</id> inside <rawData> or add an attribute <rawData id="###">

 

 

]]>
  • Mark Salamon - this would be amazing. For now there is a possible workaround

    "./itemRenderGridXML.action?metaData.siteID=" + siteID + "&metaData.sheetId=" + sheetID + "&metaData.sheetViewID=" + viewID + "&contentTypeAlias=sheet"

    Credit to Andrew Quinn for his file. Sorry can't remember which thread it was in but this is the file : https://collaborate.highq.com/sitepoint/externalAccess.action?linkParam=248Md4JKaxhUxUnOm6kiAbGBt1OCGih5Nc1xuLJitePdzoxprWhI6w%3D%3D&documentDownload=link

     

  • David Corrin  Interesting. A different view of an iSheet available from inside the browser that also includes the fileid information. Thanks!

  • David Corrin Btw, the technique I discovered works with that URL format too. Just add &metaData.itemId={ITEMID} to the end and it will limit the results to a single record. Conceivably, at the time the user clicks on a file or folder to access it, you could make the single record call out and retrieve the fileid or folderid and then take the user there. It's unlikely that the user will click on any of the files, so this should save some processing.

  • Andy Neill Has the "itemRenderGridXML" been removed in 5.7.x? I'm now getting an unhandled exception when trying to access it?

  • Dan Pryor, looks to have been replaced by the /isheetGrid.action?... call. Looks to have the same query string parameters, and XML response. FYI for others, this is different to the /sheetViewExportXML.action?... which is the official endpoint Collaborate provides - itemRenderGridXML was the internal called used by the iSheet module home page, to render the grid view.

  • We've moved entirely over to API calls now for this reason, good to see it's still an option to do in XML.

  • Thanks Andrew Quinn! It also appears to now require the: injectSheetView parameter

  • Bumping this for visibility and to see if there is currently any way to open a file directly from an iSheet XML?

    I'm currently rendering a custom isheet table on a landing page using the datatables.js library, but I'd like to link directly to a file link column contained in each record.

    As noted above by  , the XML doesn't contain the fileID. The itemRenderGridXML seems to be gone as noted too, but the isheetGrid.action mentioned by  is also returning an error from what I can see?

    Not sure how to include the "injectSheetView" parameter works, but trying "&injectSheetView=true" at least gets me past the system error, but returns what Edge is saying is broken XML.
    So, I'm not quite sure what the potential workaround may have been without getting an idea of what those two actions above used to return. Is that still the option? I'm imagining if I got an XML with all the records I could filter on a row based on title or something unique.

    Any basic pointers here appreciated.

  • Hi  ,

    Longer term, my advice is to go the iSheet API route as both ExportXML and iSheetGrid methods have their issues.

    ExportXML - As you mention, there are no doc ID's, folder ID's, attachment ID's in this export of the iSheet data to work with but one of the main isues is that ALL the data in the iSheet View is exported, so if this is in the 100's or 1000's of records, and/or scores of columns, then performance will be a factor, and the user could be waiting for the table to load as MB's of data is downloading.  Not an issue if you are confident the iSheet size will remain managable over time, but it's a question that needs answering.

    iSheetGridor RenderGridXML as it used to be called.  This is basically the way HighQ renders the iSheet grid and can change over the course of Collaborate versions as TR add functionality, or decide to change the UI look and feel.  So you will need to potentially test your parsing of the HTML within the returned data for each release.  You also have the problem that this data is paged, so you only receive the first 100 records, and need to query the next page of data until you have all the records.

    DataTables needs all the records to be able to render and use any paging/filtering functionality, unless you use the server-side deferring, in which case you really should be using the iSheet API's.

    Hybrid -  For some scenarios, like your example, we don't need the (doc) ID's to render to the UI.  The ExportXML has the name and file type which could be rendered in the table, and an onclick handler could intercept when the user wants to view/action something. It's in the handler you could then go to the iSheetGrid for just that one record, passing in itemId: .... to the helper function which will result in a dataset of either 1 (valid itemId), or 0 (invalid itemId). The advantage here is that you are only using iSheetGrid for specific column data, from a specific record, so you don't have to waste effort working out how to parse the HTML for every type of column type data there is - only for the parts of data missing from the ExportXML.

    If you still want to go the iSheetGrid route, the code below could be of use. Here we define an async generator that will help us retrieve all the records easily. You could hook it up to a progress bar if need be. Without knowing anything specific about size and shape of your data, I leave that to you, e.g.

    let $res;
    for await ($res of CommunityExamples.exportSheetXML({ 
    	siteId: 9999, 
    	sheetId: 9999, 
    	sheetViewId: 9999,
    	// itemId:9999
    })) {
    	let recCount = $res.find("rows > userdata[name='recordCount']").text();
    	let recTotal = $res.find("rows > userdata[name='totalRecordCount']").text();
        console.debug(`retrieved ${recCount} of ${recTotal}`);
    }
    
    // e.g. get all rendered data from the 'first' iSheet column - 4th cell onwards
    $res.find("rows > row > cell:nth-child(4)").map((i,el) => $j(el).text()).toArray()

    And the helper function code:

    ;(function($, window, document, undefined) {
    
    	window.CommunityExamples = window.CommunityExamples || {};
    	
    	window.CommunityExamples.exportSheetXML = async function* (params) {
    
    		let ts = Date.now(),
    			totalRecordCount = 0,
    			pageSize = 100, // doesn't seem configurable in ajax call
    			$xml = null;
    
    		let renderParams = {
    			"metaData.siteID": params.siteId || ~~window.collab_common_metaDataSiteID,
    			"metaData.sheetId": params.sheetId,
    			"metaData.sheetViewID": params.sheetViewId,
    			"metaData.itemId": ~~params.itemId,
    			"advanceSearch": false,
    			"showHeader": true,
    			"injectSheetView": false,
    			"linkSheetItem": false,
    			"allowLookupSheet": false,
    			"timestamp": ts,
    			"posStart": 0,
    			"count": pageSize
    		};
    
    		let countParams = {
    			"metaData.siteID": params.siteId || ~~window.collab_common_metaDataSiteID,
    			"metaData.sheetId": params.sheetId,
    			"metaData.sheetViewID": params.sheetViewId,
    			"metaData.itemId": ~~params.itemId,
    			"showHeader": true,
    			"injectSheetView": false,
    			"linkSheetItem": false,
    			"allowLookupSheet": false,
    			"timestamp": ts,
    			[window.collab_nonEncodedCsrfTokenName]: window.collab_nonEncodedCsrfTokenValue
    		};
    		
    		let resTotalRecordCount = $.ajax({
    			url: ["./getISheetGridRecordCount.action", $.param(countParams)].join("?"),
    			method: "POST",
    			data: {
    				"check": true,
    				"metaData.screenWidth": $(window).width(),
    				ts: ts
    			}
    		});
    
    		let resPage = $.ajax(
    			["./isheetGrid.action", $.param(renderParams)].join("?"),
    			{ dataType:"text" } // XML not well-formed so don't rely on auto-sensing
    		);
    
    		yield await Promise.all([ 
    			resTotalRecordCount, 
    			resPage
    		]).then(res => {
    			// actual total record count
    			totalRecordCount = ~~res[0].totalRecordCount;
    			// first page of results
    			$xml = $($.parseXML(res[1].trim()));
    			// totalRecordCount in XML is wrong, replace with correct value
    			$xml.find("rows > userdata[name='totalRecordCount']").text(totalRecordCount);
    			// give back xml doc with first page of results for first yield
    			return $xml;
    		});
    		
    		for(let offset = $xml.find("rows > row").length; offset < totalRecordCount; offset += pageSize) {
    			yield await $.ajax(
    				["./isheetGrid.action", $.param({ ...renderParams, posStart:offset })].join("?"),
    				{ dataType:"text" } // XML not well-formed so don't rely on auto-sensing
    			).then(res => {
    				let $page = $($.parseXML(res.trim()));
    				let $newRows = $page.find("rows > row");
    				$xml.find("rows").append($newRows);
    				// update current count of records in doc
    				$xml.find("rows > userdata[name='recordCount']").text($xml.find("rows > row").length);
    				// return back the modified xml doc which includes the next page of results
    				return $xml;
    			});
    		}	
    	};
    	
    })(jQuery.noConflict(), window, document);

    As you mentioned, the XML from iSheetGrid is malformed, the issue here is that Collaborate is returning whitespacing before the start of the xml tags, which causes some parsing tools to fail to identify as XML, so to get round this we assume the response to be text { dataType:"text" }, and we process as XML ourselves, i.e.

    let $xml = $($.parseXML(res.trim())); // trim all the prefixing whitespace

    Hope this helps,

    Andrew

  • Hi  - as always, your input in this forum is invaluable. Thanks, I will try this out in the next few days. 

    My use cases are generally very small datasets - active items on a landing page for quick access, but more importantly I hate to say - a better UX (was disappointed here, as an aside, that the proposed iSheet changes I've seen in emails still lack a modern feel).

    I take your point about the API though and really should start to play with that.