Building List screens with FilterBoxes

Hints, Tips and Tricks

Technical Hints Tips and Tricks that cover customization and development using Sage CRM. API usage and coding are covered.

Building List screens with FilterBoxes

  • Comments 25
  • Likes
 
 Custom Pages that contain Search screens are fussy about block positioning.
The search block does not work correctly if it is included into the container following the list making it more difficult to create a screen with filterbox like behaviour. The type of Screen I am aiming at is shown here. This is a known issue.

The problem can be illustrated with some example code. For instance, the following code works:


var FilterBoxBlock = CRM.GetBlock("projectfilterbox");
var ProjectListBlock = CRM.GetBlock("ProjectList");
var myBlockContainer = CRM.GetBlock("Container");
with (myBlockContainer)
{
AddBlock(FilterBoxBlock);
AddBlock(ProjectListBlock);
}
ProjectListBlock.ArgObj = FilterBoxBlock;



BUT!!!!!

This code sample does not:


var FilterBoxBlock = CRM.GetBlock("projectfilterbox");
FilterBoxBlock.NewLine = false;
var ProjectListBlock = CRM.GetBlock("ProjectList");
var myBlockContainer = CRM.GetBlock("Container");
with (myBlockContainer)
{
AddBlock(ProjectListBlock);
AddBlock(FilterBoxBlock);
}
ProjectListBlock.ArgObj = FilterBoxBlock;


All that is different is that I have moved the search block to the right hand side of the List block.

To work round this I have had to control the building of the Argument that is passed to the list block. The following code is a partial work around for this issue.
You will still have to do some fine tuning but it should give you an idea.

The code is designed to be added to the Company tab group and call a list of projects belonging to that company.


if (CRM.Mode == View)
{
CRM.Mode = Edit;
}

var intRecordId = CRM.GetContextInfo("company","comp_companyid");
var strFilterButton = CRM.Button("filter", "filter.gif", "javascript:document.EntryForm.submit();");

var projectlistBlock = CRM.GetBlock("projectlist");

var FilterBoxBlock = CRM.GetBlock("projectfilterbox");
with (FilterBoxBlock)
{
NewLine = false;
AddButton(strFilterButton);
ButtonLocation = Bottom;
ButtonAlignment = Right;
}

var SuperContainer = CRM.GetBlock("Container");
with (SuperContainer)
{
AddBlock(projectlistBlock);
AddBlock(FilterBoxBlock);
DisplayButton(Button_Default) = false;
}

//Make sure fields in filter box are each on new line.
var strArg="proj_companyid="+intRecordId;
var myE = new Enumerator(FilterBoxBlock);
while (!myE.atEnd())
{
myEntryBlock = myE.item();
if (String(Request.Form(myE.item()))!='undefined')
{
strArg+=" and "+myE.item()+" like '"+Request.Form(myE.item())+"%'";
}
myEntryBlock.NewLine = true;
myEntryBlock.AllowBlank = false;
myE.moveNext();
}

projectlistBlock.ArgObj = strArg;

CRM.AddContent(SuperContainer.Execute());
Response.Write(CRM.GetPage());


Comments
  • I've attempted the same with a custom entity's MyCRM listing. The custom entity is called "Job", and I've modified the JobUser.asp page to the following :

    <!-- #include file ="..\crmwizard.js" -->

    I get exactly the same behavior as with my Document filter - appears to the left of the action buttons instead of above, and requires two clicks of the filter button to apply the filter. Any idea where I'm going wrong?

  • I'll try to paste that again without the start and end tags:

    CurrentUser=CRM.GetContextInfo("selecteduser", "User_UserId");

    var sURL=new String( Request.ServerVariables("URL")() + "?" + Request.QueryString );

    List=CRM.GetBlock("JobUserGrid");

    List.prevURL=sURL;

    var strFilterButton = CRM.Button("filter", "filter.gif", "javascript:document.EntryForm.submit();");

    FilterBox=CRM.GetBlock("JobUserFilterBox");

    with (FilterBox)

    {

     NewLine = false;

     AddButton(strFilterButton);

     ButtonLocation = Bottom;

     ButtonAlignment = Right;

    }

    container = CRM.GetBlock('container');

    container.AddBlock(List);

    container.AddBlock(FilterBox);

    List.ArgObj = FilterBox;

    container.DisplayButton(Button_Default) = false;

    // new button

    if( true )

    {

     container.WorkflowTable = 'Job';

     container.ShowNewWorkflowButtons = true;

    }

    else {

     // remove this code to remove the standard new button

     NewButton = CRM.GetBlock("content");

     NewButton.contents = CRM.Button("New", "new.gif", CRM.URL("Job/JobNew.asp")+"&E=Job", 'Job', 'insert');

     NewButton.NewLine = false;

     container.AddBlock( NewButton );

    }

    if( CurrentUser != null && CurrentUser != '' )

    {

     CRM.AddContent(container.Execute("job_UserId="+CurrentUser));

    }

    else

    {

     CRM.AddContent(container.Execute("job_UserId IS NULL"));

    }

    Response.Write(CRM.GetPage('User'));

  • HI Guys

    I have had some sucess with adding filter boxes in the last couple of days.

    The issue is that using the 'container.AddBlock(FilterBox);' Approach is that CRM Adds it to the container as a screen.

    What you want to do is add Generate the HTML for the filter button Item and then add it to either the Screen or the Container as a Button

    'grab the actual filter box

    var filtscreen = CRM.GETBlock('SoftwareFilterBox');

    'Now grab any buttons that you want to add to the bottom of the filter

    var strFilterButton = eWare.Button("Filter", "filter.gif", "javascript:document.EntryForm.submit();");

    var strAddButton = eWare.Button('New','new.gif',eWare.URL('Software/SoftwareNew.asp'));

    'arrange the filter screen as you see fit

    with (filtscreen)

    {

    ButtonLocation = Bottom;

    ButtonAlignment = Left;

           'IMPORTANT

    Mode=Edit;

    DisplayButton(Button_Default)=false;

    AddButton(strFilterButton+strAddButton);

    }

    'OK now we have all our ducks in a row lets now have a bit of fun. we need to generate our HTML manually

    var strFilter =  filtscreen.Execute();

    var html = "";

    html+= '<table class="ButtonGroup" style="float:right;width:20px;">';

    html+= '<tbody><tr><td class="FilterButtonItem">';

    html+= strFilter;

    html+= '</td></tr></tbody></table>';

    html+= '';

    If you go to one of the Legit Sage CRM Screens that have a filter and browse the HTML using the Dev tools for the browsor that you are using. You will notice the filter and Button are wrapped in the 'ButtonGroup' HTML Class and further in the 'FilterButtonItem' HTML Class

    So now we have wrapped ours in the relevent HTML Now we can add it to the screen

    screen.AddButton(html);

    or

    Container.AddButton(html);

    Although this can be done with the 'container' class i have found that you will get slightly better results if you create a 'Custom' block

    Hope this helps some one

    Ian

  • Thanks for the great tip.

  • I'm having the same issue as Kevin Lynch with a custom filter box on a custom object list, where I have to click 'Filter' twice for it to register. Has anyone worked out what is going on?

    Here is the code I'm using:

    if (CRM.Mode == View)

    {

    CRM.Mode = Edit;

    }

    CurrentCompanyID=CRM.GetContextInfo("company", "Comp_CompanyId");

    var sURL=new String( Request.ServerVariables("URL")() + "?" + Request.QueryString );

    var FilterBoxBlock = CRM.GetBlock("ProductFilterBox");

    var strFilterButton = CRM.Button("filter", "filter.gif", "javascript:document.EntryForm.submit();");

    FilterBoxBlock.NewLine = false;

    FilterBoxBlock.AddButton(strFilterButton)

    FilterBoxBlock.ButtonLocation = Bottom;

    FilterBoxBlock.ButtonAlignment = Right;

    List=CRM.GetBlock("CompanyProductGrid");

    List.prevURL=sURL;

    List.NewLine = false;

    List.ArgObj = FilterBoxBlock;

    container = CRM.GetBlock('container');

    container.AddBlock(List);

    container.AddBlock(FilterBoxBlock);

    if( !(true) )

    {

     container.AddButton(CRM.Button("New", "new.gif", CRM.URL("Product/ProductNew.asp")+"&E=Product", 'Product', 'insert'));

    }

    container.DisplayButton(Button_Default) = false;

    if( true )

    {

     container.WorkflowTable = 'Product';

     container.ShowNewWorkflowButtons = true;

    }

    if( CurrentCompanyID != null && CurrentCompanyID != '' )

    {

     CRM.AddContent(container.Execute("pro_CompanyId="+CurrentCompanyID));

    }

    else

    {

     CRM.AddContent(container.Execute("pro_CompanyId IS NULL"));

    }

    Response.Write(CRM.GetPage('Company'));

  • With mine (and potentially Kevin's) issue(s) I've realised that the issue isn't that the first click doesn't do anything, but rather does the previous filter again, and then the new one on the second click. I.e. if you have a filter of type (with 'Type 1', 'Type 2', 'All', 'Either' options) which defaults to 'All' then changing the filter (to 'Type 1') and clicking will still show all list items, it is only on the second click (with 'Type 1' still selected) that the items are filtered to 'Type 1'. If after the first click (with 'Type 1') you change the filter (to 'Type 2') then on the second click the items will still be filtered by 'Type 1', on a third click they will then be filtered by 'Type 2'.

    Default: Show All -> Change Filter to Type 1 -> Result: Shows All -> Keep filter as Type 1 -> Result: Shows only Type 1

    Default: Show All -> Change Filter to Type 1 -> Result: Shows All -> Change filter to Type 2 -> Result: Shows only Type -> Keep filter as Type 2 -> Result: Shows only Type 2

  • As an update to my previous posts, Stephen Cochrane at Sage Developer Support was able to assist me with this and sent me over some sample code which resolved the issue. I used this to amend my code and the issue was resolved. I have copied in my new code below for anyone to use in future if they are having a similar issue:

    CurrentCompanyID=CRM.GetContextInfo("company", "Comp_CompanyId");

    var FilterBoxBlock = CRM.GetBlock("ProductFilterBox");

    var strFilterButton = CRM.Button("filter", "filter.gif", "javascript:document.EntryForm.submit();");

    var strNewButton = CRM.Button("New", "new.gif", CRM.URL("Product/ProductNew.asp")+"&E=Product");

    FilterBoxBlock.NewLine = false;

    FilterBoxBlock.ButtonLocation = Bottom;

    FilterBoxBlock.ButtonAlignment = Right;

    List = CRM.GetBlock("CompanyProductGrid");

    container = CRM.GetBlock('container');

    container.DisplayButton(Button_Default) = false;

    container.AddBlock(List);

    container.AddBlock(FilterBoxBlock);

    List.ArgObj = FilterBoxBlock;

    var whereArg = "";

    if ( CurrentCompanyID != null && CurrentCompanyID != '' )

    {

    whereArg = "pro_CompanyId="+CurrentCompanyID;

    }

    else

    {

    whereArg = "pro_CompanyId IS NULL";

    }

    if((Request.Form('HIDDENSCROLLMODE') != '2') && (Request.Form('HIDDENSCROLLMODE') != '3'))

    {

    container.Execute(whereArg);

    }

    FilterBoxBlock.AddButton(strFilterButton);

    FilterBoxBlock.AddButton(strNewButton);

    CRM.AddContent(container.Execute(whereArg));

    Response.Write(CRM.GetPage());

  • Further to Ian Urquhart's excellent idea of wrapping the filter box + button(s) in html to make it resemble the output in standard CRM pages, and then add the code as a button (that was inspired!), the following code sample generates list + filter box screens that are compatible with the 'Contemporary' AND the older (and far better in my opinion) 'Classical' CRM themes:

    CurrentCompanyID=CRM.GetContextInfo("company", "Comp_CompanyId");

    var sURL=new String( Request.ServerVariables("URL")() + "?" + Request.QueryString );

    // Get the list block

    List=CRM.GetBlock("CompanyEntityGrid");

    List.prevURL=sURL;

    // Get the filter screen block and configure it

    FilterBox=CRM.GetBlock("CompanyEntityFilterBox");

    FilterBox.NewLine = false;

    FilterBox.DisplayForm = false;

    FilterBox.DisplayButton(Button_Default) = false;

    FilterBox.ButtonLocation=Bottom;

    FilterBox.ShowValidationErrors = false;

    FilterBox.RefreshFromContent = true;

    // Get the container, add list and set it's ArgObj to the filter box

    container = CRM.GetBlock('container');

    container.DisplayButton(Button_Default) = false;

    container.AddBlock(List);

    List.ArgObj = FilterBox;

    // Compile the filter screen + buttons html

    fbHtml = "<table class="ButtonGroup"><tbody><tr><td class="FilterButtonItem">";

    fbHtml += FilterBox.Execute();

    fbHtml += CRM.Button("filter", "filter.gif", "javascript:document.EntryForm.submit();").replace("</td><td>","</td><td width="32" class="FilterIconClass">").replace("er_buttonItem ","FilterButtonItem "); //note the terminal spaces in the params in the 2nd replace!

    fbHtml += "</td></tr><tr><td class="ButtonItem">";

    fbHtml += CRM.Button("New", "new.gif", CRM.URL("Entity/EntityNew.asp")+"&E=Entity", 'Entity', 'insert');

    fbHtml += "</td></tr></tbody></table><table>";

    // Add the compiled html to the list block as a button

    List.AddButton(fbHtml);

    // Code generated by the entity wizard:

    if( false )

    {

     container.WorkflowTable = 'Entity';

     container.ShowNewWorkflowButtons = true;

    }

    if( CurrentCompanyID != null && CurrentCompanyID != '' )

    {

     CRM.AddContent(container.Execute("Enty_CompanyId="+CurrentCompanyID));

    }

    else

    {

     CRM.AddContent(container.Execute("Enty_CompanyId IS NULL"));

    }

    Response.Write(CRM.GetPage('Company'));

    Note that it isn't necessary to do a dummy container.Execute().</table>

  • Note that my code has been changed somewhat by the content management system of this website.  The line with the .replace() methods has had two additional "" tags inserted:

    fbHtml += CRM.Button("filter", "filter.gif", "javascript:document.EntryForm.submit();").replace("<table><tbody><tr><td>","</td><td width="32" class="FilterIconClass">").replace("er_buttonItem ","FilterButtonItem ");

    and there shouldn't be a </td></tr></tbody></table> at the end of my post!

  • It has meddled with that last post too.  Drop me a line if you want an unadulterated copy of the code paul dot cowper at marda dot com.