Sunday, October 9, 2011

Problem with Using SharePoint Lookup Columns in Word Documents

Document properties give you a rich user experience to maintain SharePoint metadata in word documents. You can create a document content type based word templates and add SharePoint metadata to it through the Quick Parts (in Ribbon go to: Insert ► Quick Parts ► Document Properties) easily.

One of the puzzlepart assignment, I had an issue on maintaining lookup fields in word templates. Lookup fields are displayed as dropdown in word template. The issue was some of the items were missing in the dropdown (which is available in lookup list). When I investigated it I found that the dropdown item count decided based on the default view of the lookup list.

For an example if the default view restricted to display 100 items, then in dropdown shows only 100 items. Same way you can configure the filtering or sorting order in the default view of the lookup list if you want to filter out or sort the items in word template dropdown lookup.

Sunday, February 20, 2011

How to Set SharePoint People Picker Default Value to Current User through JavaScript

With the common SharePoint field types you can specify “[Me]” in the default value property to set the current logged in user. But for the Person or Group field type they haven’t enable this feature. This is a common requirement and I needed to find a good standard approach.

We can achieve this in two scenarios:
  1. After the list item save: We can trigger a workflow and programmatically set the logged in user to the field
  2. Before the list item save: We can modify the list item add new form page to set the current logged in user using JavaScript
In my case, the requirement was second scenario and this blog post is mainly focused on that.

If we are modifying the list item add new form page to achieve this, we need to consider two things:

How to get the current user information in SharePoint context via JavaScript

For this I had to refer SharePoint 2010 - Client Object Model and how to get the logged in user information using SharePoint JavaScript api.

How to set the value to the People Picker control

I found the post on how to manipulate a list form fields using JavaScript but it doesn’t mention how to do it for the People Picker control. Unlike other form fields we can’t uniquely identify the People Picker control in html markup (Other form fields can be identified by the title attribute. Title attribute has set to the field name of list item). Therefore in my approach I had to know the parent element of the People Picker control to identify the People Picker control.

I have bundled this functionality to a JavaScript class and we can reuse it whenever needed. One thing that I learned working with Puzzlepart team was you must simplify your implementation as much as possible and isolate it in a generic manner that we can reuse it other places.

PeoplePicker Class
<script type="text/javascript">

function PeoplePicker(){

    this.context = null;
    this.web = null;
    this.currentUser = null;
    this.parentTagId = null    
    
    this.SetParentTagId = function(id){
        this.parentTagId = id;
    }
    
    this.SetLoggedInUser = function(){
        if(this.parentTagId != null){
            this.getWebUserData();            
        }    
    }
    
    this.getWebUserData = function(){
        this.context = new SP.ClientContext.get_current();
        this.web = this.context.get_web();
        this.currentUser = this.web.get_currentUser();
        this.currentUser.retrieve();
        this.context.load(this.web);
        this.context.executeQueryAsync(Function.createDelegate(this, this.onSuccessMethod), 
                                       Function.createDelegate(this, this.onFailureMethod));
    }    
    
    this.onSuccessMethod = function(){ 
        this.setDefaultValue(this.currentUser.get_title());        
    }

    this.onFailureMethod = function(){
        alert('request failed ' + args.get_message() + '\n' + args.get_stackTrace());
    }    
        
    this.setDefaultValue = function(value){         
        var parentTag = document.getElementById(this.parentTagId);
        if (parentTag != null) {
            var peoplePickerTag = this.getTagFromIdentifierAndTitle(parentTag, 'div', 
                                                    'UserField_upLevelDiv', 'People Picker');
            if (peoplePickerTag) {
                peoplePickerTag.innerHTML = value;
            }            
        }
    }    
    
    this.getTagFromIdentifierAndTitle = function(parentElement, tagName, identifier, title){     
        var len = identifier.length;
        var tags = parentElement.getElementsByTagName(tagName);
        for (var i = 0; i < tags.length; i++) {
            var tempString = tags[i].id;
            if (tags[i].title == title && (identifier == "" || 
                                tempString.indexOf(identifier) == tempString.length - len)) {
                return tags[i];
            }
        }
        return null;
    }
}

</script>
Now you can reuse this in your aspx markup:
<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">

<sharepoint:scriptlink localizable="false" name="SP.js" ondemand="true" runat="server"/>  

<script type="text/javascript">

ExecuteOrDelayUntilScriptLoaded(SetWebUserData, "sp.js");

function SetWebUserData() {
    var pplPicker = new PeoplePicker();
    // Set the parent tag id of the people the picker.
    pplPicker.SetParentTagId('ctl00_UserField_containerCell');
    pplPicker.SetLoggedInUser();
}

</script>

</asp:Content>

Saturday, September 25, 2010

Set Styles on Gaia Window Control

Recently I had to use one of the coolest controls of Gaia, the Window control which mimics the behavior of a normal desktop Window within the web page. I had some issues with that, when it came to set styles on the layout of the window. They haven’t properly documented about that.

Using Firebug I analyzed the html markup, that rendered by the window control and got to know that you need to maintain separate CSS classes with predefined suffixes (defined by Gaia team) for each main content areas in the window.

For an example if you set the Window CssClass property to “update-line”, then you need to create below CSS classes with predefined suffixes to style the Window layout (only the main content areas described here)


Area

Suffix

CSS Class Example

Whole window

"-window"

update-line-window

Content area

"-window-content"

update-line-window-content

Caption area

"-window-top"

update-line-window-top

Friday, September 17, 2010

Outlook 2010 Quick Steps Feature

Recently I have upgraded my MS Office package to 2010 and it was really cool. The Quick Steps feature that comes with the Outlook 2010 made me easier to manage my mail inbox. This feature allows you to create single-click links to perform tasks that normally require multiple steps. In my case I used this to move my emails to specific folders that I have organized in my mail box. For an example if you need to move your office related emails to the “Office” folder once you have read that. You can setup a single-click link for this and it’ll be visible in Ribbon’s Home tab in your Outlook.


Currently at office I’m using two email accounts. One is for the office related work and the other one for the customer related work. Coolest thing is based on your mail box, the single-click links will be changed on the Ribbon section.

For more Office 2010 features - 10 Things

Thursday, September 2, 2010

Decorator Pattern

Current project we are working on, they heavily used design patterns in their codebase and when it comes to do the modifications and new enhancements, we must have a good understanding on how the design patterns behave and how we can apply in a real world situation to make it more maintainable and optimizable codebase.

Therefore recently I started to do some research on this and got a clear understanding on the Decorator design pattern initially.This pattern is quite useful when you need to extend an object’s behavior dynamically. This ability to dynamically attach new behavior to objects is done by a Decorator class that wraps itself around the original class.

Following example illustrates the usage of the Decorator pattern and the way I illustrated the example was bit funny and it was an incident recently I experienced.

Let’s take a real world entity called Girl for this example. Every girl has a unique feature Smile. So we can create an interface for the Girl, that specifying we need to implement the Smile:


Now we can create an Office girl (concrete class) using the Girl interface and implement the Smile for the Office girl.


Following creates an instance from OfficeGirl and check the Smile:


The output would be:


Now let’s say there is another office girl who wanted Smile and at the same time she needs to do something else too. Let's say for an example flirting. How she can achieve this?

Now the Decorator pattern is coming to the picture. By using it, we can decorate this office girl to do the flirting thingy at the run time!

Following is how we can achieve this using a Decorator class:


Following creates an instance from OfficeGirl and decorate it via OfficeGirlDecorator and check the Smile:


The output would be:


In this example if you look at the Decorator class, it can invoke just like the original class. In most cases, method calls are delegated to the original class and then the results are acted upon, or decorated, with additional functionality.

Still not got it? For more information visit Gang of Four, Wikipedia

Tuesday, August 24, 2010

Circular Positioning in ASP .Net

In Puzzlepart projects several occasions I had to find a good solution for the circular positioning on html markup. There are many ways to do this and the team wanted to tryout using pure css styles that support in cross browsers.

Below sample code illustrates how to achieve this using css positing styles and the bit of mathematics. It’ll rotate the image based on selected angle.


Page View

Code:
using System;
using System.Drawing;
using System.Web.UI;

namespace RotationTest
{
    public partial class Rotation : Page
    {
        private const double Radius = 155;
        private readonly Point Origin = new Point(190, 195);

        protected string PositionStyle
        {
            get
            {
                var style = "visibility:hidden;";
                if (!string.IsNullOrEmpty(dropDownAngle.SelectedValue))
                {
                    var angle = Convert.ToDouble(dropDownAngle.SelectedValue);
                    var position = GetPointOnCircle(Origin, Radius, angle);
                    style = string.Format(
                            "left: {0}px; top: {1}px;",
                            position.X, position.Y);
                }
                return style;
            }
        }

        private static Point GetPointOnCircle(Point origin, double radius, double angleInDegrees)
        {
            // Convert from degrees to radians via multiplication by PI/180        
            var x = (int)Math.Round(radius * Math.Cos(angleInDegrees * Math.PI / 180.0), 
                                    MidpointRounding.ToEven) + origin.X;
            
            var y = (int)Math.Round(radius * Math.Sin(angleInDegrees * Math.PI / 180.0), 
                                    MidpointRounding.ToEven) + origin.Y;

            return new Point(x, y);
        }
    }
}
Markup:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Rotation.aspx.cs" 
    Inherits="RotationTest.Rotation" %>
<head runat="server">
    <title>Rotation Test</title>
head>
<body>
    <form id="form" runat="server">
    <div>
        <div style="width: 400px; height: 402px; background-image: url(circular-image.png);
            background-repeat: no-repeat;">            
            <img src="position-image.png" alt="position image" 
                 style="position: absolute; <%= PositionStyle %>" />                 
        </div>
        Select Angle -
        <asp:DropDownList ID="dropDownAngle" runat="server" AutoPostBack="True">
            <asp:ListItem Selected="True">0asp:ListItem>
            <asp:ListItem>60</asp:ListItem>
            <asp:ListItem>90</asp:ListItem>
            <asp:ListItem>150</asp:ListItem>
            <asp:ListItem>240</asp:ListItem>
            <asp:ListItem>320</asp:ListItem>
        asp:DropDownList>
    div>
    </form>
body>
html> 

Circular Image

Position Image

Saturday, July 3, 2010

Enum to Description

Recently we had an issue with maintaining enum descriptions in our project. The problem was descriptions duplicated several places in codebase and when it came to modify descriptions we had to modify the description everywhere. From the maintainability perspective this not a good practice and we came up with a solution by using the coolest feature Extensions methods that comes with the .NET 3.5. Following is the sample code of the solution.
using System;
using System.ComponentModel;
using System.Reflection;

namespace EnumToDescriptionTest
{
    public static class EnumExtensions
    {
        // Extension method to get the enum description.
        public static string ToDescription(this Enum val)
        {
            Type type = val.GetType();

            string name = Enum.GetName(type, val);
            FieldInfo field = type.GetField(name);

            // Check for the Description Attribute.
            DescriptionAttribute[] attributes = (DescriptionAttribute[])field.GetCustomAttributes(
                                                typeof(DescriptionAttribute), false);

            return attributes.Length > 0 ? attributes[0].Description : name;
        }
    }

    class Program
    {
        // Define the enum with description.
        public enum UserMode
        {
            [Description("Add User")]
            Add = 0,
            [Description("Update User")]
            Update = 1,
            [Description("Delete User")]
            Delete = 2
        }

        static void Main(string[] args)
        {
            // Get the enum description.
            Console.WriteLine(UserMode.Add.ToDescription());
            Console.ReadLine();
        }
    }
}