Google Analytics

Wednesday, March 14, 2018

SharePoint Document Library Metadata in Microsoft Teams

If you've started to play around with Microsoft Teams and are familiar with storing documents in SharePoint, you may have been disappointed to learn you can't see document metadata on the Files tab of your team's channel.  When I first heard this, I couldn't believe it!  How could we overlook one of the most basic reasons to use SharePoint over file shares?!

Have no fear.  After poking around a bit, it turns out Teams is almost as flexible as SharePoint.
  1. In Teams, click on the Files tab for your channel.
  2. Click 'Open in SharePoint'.
  3. Edit the view, or create a new one, and add the desired metadata.
  4. Copy the web address (something like, https://xxx.sharepoint.com/sites/ComeTogether/Shared%20Documents/Forms/AllItems.aspx)
  5. Back in Teams, add a new tab by clicking +.
  6. Search for 'web' and add the Website type tab.
  7. Fill out the Tab name and URL.
  8. Golden!
**Bonus Content
Related, someone asked me, "Wouldn't it be cool if there were a place to drop files that all channels could see, like at the root of the Shared Documents library that already has folders for each of my channels?

Why, yes.  Yes, it would.

  1. Follow the steps above.
  2. In the SharePoint view you create, set the Filter to Content Type is not equal to Folder.
  3. Celebrate!

Thursday, February 8, 2018

Upgrade SPFx from 1.3.4 to 1.4.0

I just had to upgrade a SharePoint Framework client-side web part from v1.3.4 to v1.4.0.  Here are the steps I did to complete this.

  1. Run a command prompt as admin and upgrade the yoeman generator, npm install -g @microsoft/generator-sharepoint@latest
  2. Create a new web part project using the updated scaffolding engine using the settings I used originally.  For example, this project is based on the React template.  I selected that option again.
  3. In the project I was upgrading...
    1. Delete the node_modules folder and the package-lock.json file
    2. Compare and copy relevant packages/versions into your package.json file
    3. Replace the tsconfig.json file with one from the newly generated project
    4. npm install
    5. gulp clean
    6. gulp build
    7. Address any build errors.  For example, in my project I wasn't doing some Date casting correctly.  Typescript did a better job of identifying this and I had to correct those errors.

Thursday, May 8, 2014

Output Raw XML from New Content By Search Web Part

Following this blog post in an attempt to reuse some custom XML developed for SharePoint 2010, I ran into a problem with this technique for outputting raw XML from search in SharePoint 2013.  It seems other have had the same issue.

This is what I came up with to help.  It's not pretty or perfect, but it'll do for now and gives a "decent" picture of what's going on in the XML.

<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
    <xsl:template match='/'>
        <xsl:apply-templates />
    </xsl:template>

    <xsl:template match="ResultTable">
        <h1>ResultTable</h1>
        <xsl:call-template name="out">
            <xsl:with-param name="in" select="ResultTable" />
        </xsl:call-template>
        <xsl:apply-templates select="Rows" />
    </xsl:template>

    <xsl:template match="Rows">
        <h1>Rows</h1>
        <xsl:call-template name="out">
            <xsl:with-param name="in" select="Rows" />
        </xsl:call-template>
        <xsl:apply-templates select="Row" />
    </xsl:template>

    <xsl:template match='Row'>
        <h1>Row</h1>
        <xsl:call-template name="out">
            <xsl:with-param name="in" select="Row" />
        </xsl:call-template>
    </xsl:template>
   
    <xsl:template name="out">
        <xsl:param name="in" />

        <table style="border: 1px solid #000;">
            <xsl:for-each select="*">
                <tr>
                    <td style="border: 1px solid #000;">
                        <xsl:value-of select="name()" />
                    </td>
                    <td style="border: 1px solid #000;">
                        <xsl:value-of select="." />
                    </td>
                </tr>
            </xsl:for-each>
        </table>
    </xsl:template>
</xsl:stylesheet>

Monday, May 9, 2011

SharePoint 2010 Error Logging

New to SharePoint 2010 is the ability for developers to readily log to either the SharePoint Unified Logging Service (ULS) or to the Windows application event log.  What a win-win-win situation for all involved, from the developer to the end user to the admin.  The namespace to investigate if you're interested in performing either of these tasks is Microsoft.SharePoint.Administration.  More specifically, the classes under the prefix SPDiagnostics (SPDiagnosticsArea, SPDiagnosticsCategory, ...).  Even more specifically, the methods SPDiagnosticsService.WriteTrace (for ULS logging) and SPDiagnosticsService.WriteEvent (for Windows application event logging).

A great place to put this type of logging is in web parts.  Always be sure to wrap your CreateChildControls or Render methods with a try/catch.  There's nothing worse than the whole page blowing up just because one piece of the page has failed unexpectedly.  On to the example....

catch (Exception ex)
{
     // Get the local instance of the diagnostics service
     SPDiagnosticsService diagService = SPDiagnosticsService.Local;
     // Log the event under the SharePoint Foundation, Web Part category
     SPDiagnosticsCategory diagCategory = diagService.Areas["SharePoint Foundation"].Categories["Web Parts"];
     // The exception message to write to the log
     string exceptionId = "Web Part Exception Unique ID: " + Guid.NewGuid().ToString();
     string exceptionMsg = exceptionId + " " + ex.Message + ex.StackTrace;

     // Log the event as unexpected
     diagService.WriteTrace(0, diagCategory, TraceSeverity.Unexpected, exceptionMsg);

     (...)
}

At this point, it'd be good to write something back to the user of your web part.  Depending on the method you're overriding, you would replace the above ellipsis with code to either add some literal controls to the web part controls collection, or by writing directly to the HTMLTextWriter provided.

     // Provide the user some nice feedback with a follow-up for the admin
     writer.WriteLine("An unexpected error has occurred.");
     writer.WriteBreak();
     writer.WriteLine("If this problem persists, please contact your administrator.");
     writer.WriteBreak();
     writer.WriteBreak();
     writer.WriteLine("Events have been added to the ULS log.");
     writer.WriteBreak();
     writer.WriteLine(exceptionId);

Also new to SharePoint 2010 is a more useful error messaging system in general.  If a page errors out, a dialog box containing a correlation ID is made available for admins to use in troubleshooting.  You may be asking yourself, how do I include this correlation ID into my message back to the user.

I did a lot of digging and found this post by Tobias Zimmergren.  In the section titled "Get the current Correlation ID by using code", he talks about just how to do this.  However, in my opinion, this is overkill.  I say this because...
1.  The correlation ID is not unique to the error itself.  It really reflects the page request as a whole.  Therefore several lines, at least in the ULS log, will have this correlation ID stuck on the end of them.
and
2.  You're already providing the system administrator a new GUID that uniquely identifies this error.

Thursday, April 28, 2011

A Poor Man's Date Filter Web Part

Recently, I was asked to create a date filter to give users an easy mechanism to filter down some data in a list.

Normally, I'd create myself a view on the list then edit the page and add a date filter web part.  At that point, all you have to do is wire up the date filter and the list view web parts and you're done (see this article for more information).

That's all fine and dandy if you've got the SharePoint Enterprise license.  All of the filter web parts are in the Enterprise feature.  What if you don't have Enterprise?  Am I out of luck?

Absolutely not.  Instead of the Date Filter Web Part, why not slap on a Form Web Part?  This little guy lets you define your own HTML to filter with.  Need a text box?  Great.  Need a check box, dropdown list, ...?  Great.  Need a calendar?  Uhm...wait, there's no easy HTML control for a date picker.

Ah, but you're in SharePoint.  SharePoint has date pickers all over the place.  An easy way to toss one on a page is to add a Microsoft.SharePoint.WebControls.DateTimeControl server control to it.  If we can figure out what that control adds to the page, we're golden.

Modify the Form Web Part and add the below HTML to the Source Editor.  The text is red is what renders the date picker functionality onto the page.

<div onkeydown="javascript:if (event.keyCode == 13) _SFSUBMIT_">
  <SCRIPT language='javascript' src='/_layouts/datepicker.js'></SCRIPT>
  <SCRIPT language='javascript'>var g_strDateTimeControlIDs = new Array();</SCRIPT>
  <SCRIPT language='javascript'>g_strDateTimeControlIDs[""] = "ctl00_PlaceHolderMain_ctl00_Date";</SCRIPT>
  <input name="ctl00$PlaceHolderMain$ctl00$Date" type="text" maxlength="45" id="ctl00_PlaceHolderMain_ctl00_Date" class="ms-input" AutoPostBack="0" />
  <A href="#" onclick='clickDatePicker("ctl00_PlaceHolderMain_ctl00_Date", "\u002f_layouts\u002fiframe.aspx?&cal=1&lcid=1033&langid=1033&ww=0111110&fdow=0&fwoy=0&hj=0&swn=False&minjday=109207&maxjday=2666269&date=", ""); return false;' >
    <IMG id=ctl00_PlaceHolderMain_ctl00_DateDatePickerImage src="/_layouts/images/calendar.gif" border="0" alt="Select a date from the calendar."></IMG>
  </A>
  <IFRAME id=ctl00_PlaceHolderMain_ctl00_DateDatePickerFrame SRC="/_layouts/images/blank.gif" FRAMEBORDER=0 SCROLLING=no style="DISPLAY:none;POSITION:absolute; width:200px; Z-INDEX:101;" title="Select a date from the calendar."></IFRAME>

  <input type="button" value="Go" onclick="javascript:_SFSUBMIT_"/>
  <input type="button" value="Reset" onclick="javascript:_SFRESET_"/>
</div>

Awesome!  Now we've got a date picker in our Form Web Part.  All that's left is to wire it up to our list view web part the same way we always did.