Sunday, January 28, 2007

I love Sharepoing!

Half a year ago I posted a post about a possible bug in workflow schema, and as a side note I asked my readers (thats you) if it happens to you that you write sharepoing instead of sharepoint.

I had a comment from someone telling me it happens to him, reassuring me I am not the only one in the world making that mistake.

Since then I have been tracking the elusive "sharepoing" on the internet forums and blogs. Last week I found a blogger called Raghu Iyer who also made the mistake and I posted a comment for him, welcoming him to the sharepoing community. Sadly, Raghu fixed his mistake so you will not see it there.

Today I ran a google search and it turns out there are 971 instances of the sharepoing on the google index! I definitly liked Heather's (MVP) Avoid "SharePoing of the Living Dead" (I wonder if she noticed).
Another cool highlight is this russian blogger (post is in english) who apperantly types everything by hand, since all his namespaces are "Microsoft.Sharepoing.SPList".
Most of the other search results are from forums and discussion boards, but I am sure if we start a sharepoing movement, we can change it! I put a challange to the sharepoint community - If you have a blog, make a diliberate post with "sharepoing" at the header, and explain this (point to this posting) and lets watch this wonderful word gets the honor it deserves.
By the way, I would copyright the right to sharepoing, but I dont have the resources.

Wednesday, January 24, 2007

Teach the Content Query Web Part how to display a link list


A small problem with the content query web part is when you connect it to a link list is that it doesnt know what is the title of the link, and the link it is rendering point to the list item view page and not to the target of the link:



The web part renders (blank) as title

Connecting a CQWP to a link list

Connecting a CQWP to a link list

The web part renders (blank) as title, and the link points to the item



To fix this, we need to do two things:

  • Teach the web part to get the "URL" field from the list

  • Define the style for a link list that will render the link properly using the URL field



  • Lets start.


    Begin by connecting a query webpart to a link list like shown in the images above. Make sure there are some links in the list so you can track the change.
    After this, you should get the same look that you saw in the second image above.


    Export the web part - open the edit menu of the web part, and choose export to save it:




    After you save it to the hard disk, open it for editing in your text (or xml) editor of choice (notepad is ok):




    In the file, find the property "CommonViewFields". It should look like this:

    <property name="CommonViewFields" type="string" />


    Change it to include the URL field:

    <property name="CommonViewFields" type="string">URL,text</property>



    Save and import the file into the page (you can delete the web part you had on the page):

    Import web part menu

    Click the "Page" menu and select add webparts - import




    upload the web part file

    Browse to the file you just saved, and click Upload. drag and drop the web part to the page.




    So now the web part "knows" about the URL column. Now we have to "teach" it to show it properly.



    Open the site in SharePoint Designer. Under the root, find the "Style Library" folder, and then the "XSL Style Sheets" folder. right click the "ItemStyle.xsl" file and choose "checkout":





    After checking it out, open it. We are looking for the "NoImage" template. It should start with a line like this:

    <xsl:template name="NoImage" match="Row[@Style='NoImage']" mode="itemstyle">



    Copy the entire template (from the "<xsl:template" to "</xsl:template>") and paste it underneath. This is where we will create our own style - just for links.
    In the new section, change the code using the following rules (full code to follow):

    1. Rename "No Image" to "LinkList"
    2. Change the "href" attribute to point to the URL column, the text before the comma.
    3. Change the link text to point to the URL column, the text after the comma


    Here is the code:





    <xsl:template name="LinkList" match="Row[@Style='LinkList']" mode="itemstyle">
    <xsl:variable name="DisplayTitle">
    <xsl:call-template name="OuterTemplate.GetTitle">
    <xsl:with-param name="Title" select="@URL"/>
    <xsl:with-param name="UrlColumnName" select="'URL'"/>
    </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="LinkTarget">
    <xsl:if test="@OpenInNewWindow = 'True'" >_blank</xsl:if>
    </xsl:variable>
    <div id="linkitem" class="item" >
    <div class="bullet link-item">
    <xsl:call-template name="OuterTemplate.CallPresenceStatusIconTemplate"/>
    <a>
    <xsl:attribute name="href">
    <xsl:value-of select="substring-before($DisplayTitle,', ')">
    </xsl:value-of>
    </xsl:attribute>
    <xsl:attribute name="title">
    <xsl:value-of select="@Description">
    </xsl:value-of>
    </xsl:attribute>
    <xsl:value-of select="substring-after($DisplayTitle,', ')">
    </xsl:value-of>
    </a>
    </div>
    </div>
    </xsl:template>



    Save the file and publish it.
    Warning - if you paste it wrong or delete some character by mistake, all your content query web parts may stop working in the site collection. If that happens, either check out the file and use the undo function (if it's still in memory) or right click the file and use the version history to roll back. You may also want to download the file as a backup.



    Go back to the web part page with the uploaded webpart that has a referance to the URL field (the one we imported earlier), and open the web part properties. This may take a while, but under "Presentation" - "Styles" - "Item Style" you should have the "LinkList" style to select. Select it and click ok.





    The web part should now display the titles of the list items, and the link should point at the link target. Also, the description of the link should appear as a tool tip when you hover over the link:




    note - my site has a modified style sheet, so bullets look like ">". You'r links should appear like regular bullets.

    Tuesday, January 23, 2007

    Showing the description of a page in the Content Query Web Part as rich HTML


    The Content query web part is a wonderful way to aggregate data into a page. A common use of it is to show "news" pages in the home page of a publishing site. This is well enough, and it even has several styles to pick from :




    If you want to customize one of the styles or create your own you can do that by editing the xslt data

    Problem
    Some of the built-in styles include the description field and display it, but my problem was that the description was plain text. It even ignored line breaks that the users wrote. And that is a big problem if you want a summary of the article in your home page with a "read more..." link. For example, if the description the user wanted on the home page was:

    This is a very important description
    that has a line break.


    He would instead get:
    This is a very important description that has a line break.


    Solution?Since the pages sit in a document library, and since document libraries do not support rich text fields (damn it!), I had to think of a quick and ugly solution - paste html text into the description. So if the description was to be:

    This is a very important description
    that has a line break.

    the user had to paste the html equivalent:

    This is a very <strong><font color="red">important</font></strong> description<br>that has a line break.

    Almost!

    So I tried this, and found a flaw. The Content Query web part would display the text as-is and would not format it as rich html.

    XSL to the rescue


    To resolve this, there is a simple tweak you can do on the itemstyle.xsl file in the site. Open the site in SharePoint Designer, and navigate to the "Style Library" folder, and into the "XSL Style Sheets" folder. Check out and open the ItemStyle.xsl file, and in it find the style that you are using in the webpart, where you want to display the description as rich text.

    A quick way to do that would be to search the file for the text

    <xsl:value-of select="@Description" />



    Add
    disable-output-escaping="yes"
    inside the tag, so that the end result is:

    <xsl:value-of select="@Description" disable-output-escaping="yes" />

    With this quick change, the html code the user inputs in the description field will be displayed as rich text. The only danger in this is that the user will make a mistake, not close one of the fields and cause havoc on the page. So make sure your users are aware of the risk, and maybe write an event handler or workflow to validate the html. I would recommend just implementing an approval workflow that checks the validity of the html.

    Monday, January 22, 2007

    InfoPath form Services - implementing a Master-Detail on the web


    If you ever tried publishing a form to the web using infopath form services, you probably know that one compatibility issue you will have is with master-detail (also known as "cascading dropdowns") fields.


    Master-detail basically means when you have two fields (usualy dropdown boxes) and you want the options in the second field to change based on the choice the user made in the first field.


    For example, I have a dropdown called "States", and a dropdown calles "Cities". Now I want when the user chooses a state, to only show cities within the chosen state.
    This is easy to do in infopath - just connect the dropdowns with a little configuration. But when you try to publish the form to a web form, it will tell you that the master-detail will simply not work in the web form. It's not supported.

    To the rescue!

    Let me use the above example, showing you how to get it to work.

    First, you will need to set up two seperate data connections - one for the states, and one for the cities. I will use sharepoint lists in this example (and on the way tell you a small trick that my colluege Rai Umair showed me).

    Lets create the lists:


    The states list





    Set up a lookup into the states list from the cities list





    The cities list


    Now that we have our lists set up, lets build a simple infopath form that will show them:


    • Create a blank new form in infopath
    • Add the connection to the "States" list:
      Tools->Data Connections->Add->Receive Data->SharePoint library or list->link to the site->Select "States"->Select "Title"->click next until the wizard finishes.
    • Add the connection to the "Cities" list:
      ok, here is the trick from Rai. instead of adding the connection to the list as a sharepoint library connection, we will instead add it as a XML connection, and point it to a url that will allow us to filter the list. This is a nice trick and I thought you should see it. The whole idea is to set up a connection that will be able to filter based on a user selection. if you have other methods of doing that, feel free.

      • First we need to find out the GUID (the id) of the cities list. To do that, open the cities list in the browser, and click on "Settings"->"List Settings". The id of the list is in the address bar - after the bit that says "?List=".

        For example, if the address bar shows
        "http://server/infopath/_layouts/listedit.aspx?List=%7B7DF67EB0%2D723A%2D4897%2DA461%2D09EA9CC0D90C%7D"
        that means the ID is the bit painted in red.
        But, if you will note, it is url-encoded. you will need to replace "%7B" with "{" and "%7D" with "}" and "%2D" with "-" so the end result is: {7DF67EB0-723A-4897-A461-09EA9CC0D90C}
      • Once you have the ID, use it to construct a url like this:

        http://server/infopath/_vti_bin/owssvr.dll?Cmd=Display&List={put the ID here}&XMLDATA=TRUE

        Example: http://server/infopath/_vti_bin/owssvr.dll?Cmd=Display&List={7DF67EB0-723A-4897-A461-09EA9CC0D90C}&XMLDATA=TRUE

        If you open it in Internet Explorer, you should see something like this:



        This gets us the content of the cities list in an XML format that Infopath knows how to read.
      • Go back to infopath, add a new datasource ->Receive Data->XML Document-> paste the path we constructed above->choose "Access the data from the specified location"->Give the data connection a name (Cities) and clear the "Automatically retrieve data when form is opened" (important!)

    • Your data sources screen should now contain two data sources:



    • Lets add two fields into the main data source - City and State:



    • Lets add the two fields to the form as drop downs:




    • Change the properties of the "State" drop down to get the values from the states data source:





    • set up the properties of the city in the same fashion:



    • Ok, test the form. The states drop down should show the states, while the city dropdown should be empty since we told the datasource not to load the values on form load.






    Now that our form is ready, all we need to do is make sure that when a user picks a state, the form loads the cities. Again, it would have been a simple task if we didnt want to publish the form to a web form, but since we do - we will have to do it by code.

    Small note - my code is in C#, and by default Infopath is set to use VB.NET. I suggest that you change the setting for this form - open Tools->Form Options->Programming, and select C# as template code language.


    While you are in the tools->options, you may as well set the compatibility to "Design a form template that can be opened in a browser or infopath"


    Right click the "State" dropdown, and select "Programming"-"Changed Event":





    Visual studio has opened, with an empty new event "State_Changed". Paste the following code into the module


    public void State_Changed(object sender, XmlEventArgs e)
    {
    SetCitiesOptions();
    }

    private void SetCitiesOptions()
    {
    FileQueryConnection q = (FileQueryConnection)this.DataConnections["Cities"];
    q.FileLocation = q.FileLocation + "&FilterField1=State&FilterValue1=" + GetStateValue();
    q.Execute();
    }

    private string GetStateValue()
    {
    XPathNavigator nav = this.CreateNavigator();
    string filterValue = (string)nav.SelectSingleNode("/my:myFields/my:State", this.NamespaceManager).ValueAs(typeof(string));
    return filterValue;
    }


    So, what does this code do?

    • The "GetStateValue" function simply uses the XPathNavigator to get the value the user selected in the "State" field. We can also get that from the "e" object of the event, but to simplify the readability of the code I used functions here.


    • The "SetCitiesOptions" changes the url of the XML file that the cities data connection is using, and adds a filter to it. the filter syntax is "FilterField1=[name of field]&FilterValue1=[Value you want to filter".

      So basically, you can create whatever filter you want on the fields, and as many filters as you want (in an "And" chain).


    • The changed event for the states just makes sure the form loads the city data with the appropriate filter!


    this will work on the client side, but not on the server side. why? because we are doing the re-query by code, the server will not refresh the page (postback). So to force a post back you will have to add a rule to the "State" dropdown. The rule will force the page to get the new information.
    To do that, right-click the "State" dropdown, and choose "Rules" from the menu. Click "Add" to create a new rule and then "Set Condition" to "State is not blank" and add an action "query using a dataconnection" from cities:









    How easy is that?




    Try and preview you'r form in infopath. Now when you select a state, the cities box should show options based on the selection you made:





    Now publish the form to a sharepoint forms server. Since this is a long proccess, and there are enough articles about this on the net, I will leave you to it.




    When you test your form on the web, it should cascade the field:




    You will note that the refresh is done using AJAX, so the page does not postback, but instead just waits for a second (with a nice bar) and then populates the data.




    References and thanks

    • I want to thank my colleague Rai Umair for the "/_vti_bin/owssvr.dll" trick. May he resume blogging again soon.
    • I want to thank Ed Torres for forcing me to take a look at this and listening to me complain as I tried to make this work.

    • While I was writing this article, a colleague (Lee Marriage) sent me a link to an article doing something very similar by Scott Heim from Microsoft's Infopath team. His solution is to use a web service to filter the list items (I like Rai's trick better. no code needed, and easier to deploy) and using a similar rule like I did to refresh the data.

    MOSS gets good reviews - "Is Microsoft's SharePoint 2007 a golden app?"

    take a look at "Is Microsoft's SharePoint 2007 a golden app?" in computerworld.com about MOSS.
    These people did do some real research and are not spouting silly one-liners such as "doesn’t necessarily encourage lot of collaboration".
    The article prounounces MOSS as being such a big collaboration tool that most organizations feel a need to block and limit some of it (sounds familiar? I said that last week!).
    One thing to note in the article - they noted that the BDC is a task for developers (which I agree with) but then they write "a Visual Studio job, no doubt.". Well, just to make things precise - no, you dont need visual studio - any XML editor or even notepad is enough to create a BDC definition. The problem starts when you want to expose your application's data - and if the data is not in SQL, you will need to develop a web service for it, and that's where Visual Studio may come in (you can use other technologies or IDE - no one is forcing you).

    Saturday, January 20, 2007

    Blog Logo

    Do you like it? I made it myself (any volunteers to make this better?):

    Wednesday, January 17, 2007

    Call for Microsoft - SharePoint as Open Source!

    In one of the most interesting articles I've read lately, Stephen Walli is explaining why and how sharepoint should be made open source.
    It is very interesting and I wonder if someone from Microsoft will read this and say "hmmm...let's do it!".
    I really hope so, because I can think of so many changes I would like to do to the sealed classes, and I can only imagine what the hard core developers would do. Next time we find a bug, we can fix it ourselves and not have to wait in queue for the service pack, while our customer is canceling the project.
    Microsoft will gain more developers living sharepoint inside-out and more and more integrating products will come out.
    What do you think?

    Monday, January 15, 2007

    Permission to use my samples

    In a recent comment for one of my posts someone called "S Jaiswal" left a comment asking for my approval to use my code samples in presentations. Since he didnt leave any contact details, I will post this publicly to all of you.

    The rule here is like in the academic world - use it all, change it as much as you want and go wild. Just one thing - give credit when it's due. If you used one of my blog posts to write a blog post - put it in the notes of the post, with a link to the article in my blog.
    If you do a presentation and show something that you learned from me, put a link to my blog and to the article.

    That's it - just use common sense. If someone helped you, give him the credit. I hope I get more such comments - its a wonderful thing to know that the information I post here is getting used. please let me know if you use it (I would love to get a copy of the presentation to see how you did it!)

    A final note to people who organize sharepoint user groups and\or techeds or events like that - I will be happy to get invited to such events. I am very active in the Canberra sharepoint user group, and I have done presentations on the Sydney one as well, not to mention 2 lectures in Teched Israel 2003. I am more then willing to come (you just have to get me there...from Australia).

    SharePoint is misunderstood - it's the corporate world that is still old.

    I today's article in the 360techblog, a guy called Ray Velez from Avenue A | Razorfish is quoted to say:

    ...that price isn’t the only reason SharePoint isn’t getting love from the web 2.0 crowd. It may be very powerful, but it’s also complicated. “Trying to move a portal server is like moving a battleship,” he says.

    Moreover, he says, Microsoft’s products are built on the old intranet model that doesn’t necessarily encourage lot of collaboration. They’re designed for the old corporate world of command-and-control, enabling layers of permissions that can stifle spontaneity. With wikis and blogs, it’s all much more accessible.”

    Although the entire artical deals with the microsoft vs google, and the microsoft office 2007 release, and sharepoint 2007 bdc as a killer, this guy seems to be talking about sharepoint 2003!

    It's either that or he doesnt know what he is saying. SharePoint 2007 encourages collaboration so much out of the box, that most of my clients ask me to restrict the collaboration features, because they are afraid the users will spend time "collaborating" instead of "working".
    Mr. Velez needs to understand that while sharepoint is designed to allow top notch collaboration, most of the corporate world is not prepared to use it. They install sharepoint, and then spend a lot of money to customize it so that collaboration is trimmed to a minimum.
    It's not SharePoint that is "designed for the old corporate world" - its the corporate world that is still old.

    It's a pity sharepoint keeps getting bad reputation because people who havent really been using it, or who are not sharepoint professionals have been covering it in the media. I saw a gartner document about half a year ago that totaly discarded what sharepoint 2007 could do, and reviewed the brand name sharepoint as if 2003 was all there was. I admit that 2007 needs a lot of work, and 2003 wasn't perfect, and I would be the first to shout that the 2001 version was a disaster, but saying that sharepoint is built on the old intranet model? what is that???

    Sunday, January 14, 2007

    Scripts, styles and images dont work on a SharePoint site

    There are a lot of reasons why images, styles and scripts will refuse to work for you on a sharepoint site. I have come across some of them, and I want to share how to troubleshoot this.

    One reason this may happen is that your Internet Explorer is blocking the scripts. I had a lot of people complaining about how they installed sharepoint on the server, then created a web site, then tried to create a list item or upload a document, and non of the buttons would work!
    You will find that often this is accompanied by sharepoint constantly asking you for authentication each time you load a page, and sometimes more than once for each page before letting you see the page.
    Cause
    This was because they were working from the server, which by default has the "Internet Explorer Enhanced Security Configuration" installed.
    Solution
    If you must work from the server itself, either remove the "Internet Explorer Enhanced Security Configuration" (control panel->add remove programs->add/remove windows components) or add the site to the trusted sites list (not guaranteed to work. I suggest you remove the security block).

    Another reason is a problem with the alternate path mapping in central admin. The Alternate Path Mapping are not configured so that the path you are trying to use is properly managed by sharepoint. For example, you may be using http://localhost while sharepoint is configured to accept http://portal.
    Cause
    I dont know why this happens, most of the time the alternate paths are configured correctly for you automtically. But I have seen a server (just today I had 2!) that lost it...
    Solution
    Open the SharePoint Central Administration Page, go to the Operations page, and click on "Alternate Access Mapping". Make sure that the url you are trying to use is in the list, and if not- add it!

    These are the two instances of this problem that I have witnessed. Got more? comment!
    note - if you do comment, feel free to leave your name - otherwise I cant give credit where its due. Also, if you ask questions, leave a way to contact you! the best way is to register in blogger to get a user name and password (not a blog) so I can know who left the comment.