Wednesday, April 20, 2011

ECMA Script Client Object Model Error: The property or field has not been initialized…


I wrote the following code:

function initialize()
{
ctx = new SP.ClientContext.get_current();
currentweb = ctx.get_web();
ctx.load(currentweb, 'Id');
var webid = currentweb.get_id();
 
ctx.executeQueryAsync(Function.createDelegate(this, onSuccess), Function.createDelegate(this, onFail));
}


Notice the bold and italic line of code that will generate the following error:
Message: The property or field has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested.

Solution:

  • Add ExecuteOrDelayUntilScriptLoaded(initialize,'SP.js'); in the code block to ensure the SP.js fully loaded before using it.
  • Place var webid = current web.get_id() in the function onSuccess. It seems that you can get the web properties in the same function of it’s being loaded

Extended List<> functions

I was working on a web part one day and tried to use List<string> to store a projected field of list items. Because the projected filed might be duplicated in the list, I need to do a distinct. But the List object in System.Collections.Generic doesn’t have that function available. After doing some research, I found that it’s the System.Linq which extends the distinct function along with other useful functions. What you need to do is to add System.Linq in the using statement and you get all the extended functions.

Thursday, April 14, 2011

Search against a list by using FilterName FilterMultiValue with Pagination

Some blogs talked about using FilterName FilterMultiValue as query string in the url to search on a list (you can google the two names and see what I mean) but there are some issues in this solution. One big problem is pagination. After navigate to the second page, the results are not filtered by the keyword anymore, instead it shows up all records on that page.

I recently worked on this issue and have a workable solution to it. My thought was to rewrite the url after user clicked the page button in the OnPreRender event. This solution basically fires a second redirection with the rewritten url which contains the FilterName FilterMultiValue query strings. You can also put the keyword back in the text box in the OnPreRender event which is a bonus.

It’s a web part created in a sandboxed solution. Here is the sample code:

protected override void CreateChildControls()
{
    //the search keyword box
    var searchBox = new TextBox();
    searchBox.ID = "keyword";
 
    ...
 
    //the literal to hold the javascript
    var literal = new Literal();
    literal.ID = "script";
 
    ...
 
    //search button
    var searchButton = new ImageButton();
 
    ...
}
 
protected override void OnPreRender(EventArgs e)
{
    try
    {
        base.OnPreRender(e);
        
        var keyword = (TextBox)this.FindControl("keyword");
        var script = (Literal)this.FindControl("script");
        if (keyword == null || script == null) return;
 
        //rewrite the url
        var url = HttpContext.Current.Request.Url.AbsoluteUri;
        if (url.IndexOf("FilterName=") <= 0 && url.IndexOf("FilterMultiValue=") <= 0)
        {
            if (!url.EndsWith("aspx") && keyword.Text.Trim() != "")
                script.Text = "<script type='text/javascript'>window.location='" + url + "&FilterName=" + [FieldToSearch] + "&FilterMultiValue=*" + keyword.Text + "*';</script>";
        }
 
        //set the search box text
        if (url.IndexOf("*") > 0)
        {
            var array = url.Split('*');
            if (array.Length >= 1)
                keyword.Text = array[1];
        }
 
    }
    catch { }
}