Showing posts with label JavaScript. Show all posts
Showing posts with label JavaScript. Show all posts

Tuesday, 28 October 2014

Limit Regarding Lookup in MS Dynamics CRM 2013

So Today we had an interesting requirement: We had a custom entity, called Paper, for which we wanted to limit the entities that could be selected for the regarding lookup.

I can't come up with a supported way of doing this so this is the unsupported way:

In essence, this will limit the Regarding to new_keyissue and new_goal.

You'll need to fire it on the onChange event like this, NEW.Paper.limitRegardingLookup.

if (typeof (NEW) == "undefined")
{ NEW = {}; }
NEW.Paper = {
    limitRegardingLookup: function () {
        
        var KeyIssueOTC = GetEntityTypeCode("new_keyissue");
        var goalOTC = GetEntityTypeCode("new_goal");
  
        var ObjectTypeCodeList = KeyIssueOTC + ", " + goalOTC;
        var LookupTypeNames = "new_keyissue:"+ KeyIssueOTC + ":Key Issues,new_goal:" + goalOTC + ":Goal";
        
 Xrm.Page.getControl("regardingobjectid").setFocus(true);
  
        document.getElementById("regardingobjectid_i").setAttribute("lookuptypes", ObjectTypeCodeList);
        document.getElementById("regardingobjectid_i").setAttribute("lookuptypenames", LookupTypeNames);
        document.getElementById("regardingobjectid_i").setAttribute("defaulttype", KeyIssueOTC);

    }
};

function GetEntityTypeCode(entityName) {
    try {
        var lookupService = new RemoteCommand("LookupService", "RetrieveTypeCode");
        lookupService.SetParameter("entityName", entityName);
        var result = lookupService.Execute();
        if (result.Success && typeof result.ReturnValue == "number") {
            return result.ReturnValue;
        }
        else {
            return null;
        }
    }
    catch (ex) {
        throw ex;
    }
}

Monday, 20 October 2014

Validating SharePoint file names in JavaScript

SharePoint limits the valid characters of file names, which can be a problem, so to prevent this issue, we use this function to validated filenames in our Web App that integrates with SharePoint.

var validateFileName = function (value){

var specialCharacters = new RegExp("[\\\\\/:*?\"<>|#{}%~&]");

if (specialCharacters.test(value)) {      
 return true;
}
else{
 return false;
}

}
Only thing to note is that \\\\ is needed to represent \ in the regular expression, see this for more details

Wednesday, 23 July 2014

TIL - Hidding HTML elements with jQuery in IE.

The snippets of code below are equivalent, however the code in red does not work in IE (at least IE 9 and 11)

$('#myid').prop('hidden', true);
$('#myid').hide();

$('#myid').prop('hidden', false);
$('#myid').show();

Monday, 21 July 2014

Update Entity from JavaScript in Ms Dynamics CRM 2011/2013 using OData endpoint

Posting this for future reference:

function updateEntity(entityName, id, entity ) {

    var url = oDataUrl + "/" + entityName + "Set(guid'" + id + "')";

    entityData = window.JSON.stringify(entity);

    return $.ajax({
        type: "POST",
        contentType: "application/json;charset=utf-8",
        datatype: "json",
        data: entityData,
        url: url,
        beforeSend: function (x) {
            x.setRequestHeader("Accept", "application/json");
            x.setRequestHeader("X-HTTP-Method", "MERGE")
        },
    });
}
entityName is the logical entity name.
id is the Id of the record that we want to update
entity is a object that contains that values that need changing.
 e.g.:
 account = {};
 account.Name = "New Name"; 

 oDataUrl is the Url of the OData endpoint for your organization

Monday, 7 April 2014

Delete Entity in Ms Dynamics CRM 2011/2013 using OData endpoint

This is really part of the brain dump series but haven't really had the time until now.

So to delete an account it would be invoked like this

deleteEntity("AccountSet","ef02108a-0098-e311-81c2-d89d6763fc38'")

var deleteEntity = function(EntitySet, Id)
{
 url = Xrm.Page.context.getClientUrl() + "/XRMServices/2011/OrganizationData.svc/";
 url += EntitySet + "(guid'" + Id + "')"

 delete(url).fail(function(){alert("An error ocurred deleting " + Id)})

}

var delete = function(url)
{
 return $.ajax({
 type:"DELETE", 
 url:url,
 beforeSend:function(x){x.setRequestHeader("Accept","application/json")},
 });
}
Also, jquery needs to be loaded if you are using Dynamics CRM 2011

Monday, 17 March 2014

Create Entity in Ms Dynamics CRM 2011/2013 using OData endpoint

This is really part of the brain dump series but haven't really had the time until now.

Two entities,  Author (dab_author) and Book (dab_book) with a 1:N relationship between them.

The challenge is to create an new book for a particular author, from the author form.


var createNewBook = function()
{
 url = Xrm.Page.context.getClientUrl() + "/XRMServices/2011/OrganizationData.svc/dab_bookSet";
 author = Xrm.Page.data.entity.getId();
 dab_book = {};
 dab_book.dab_name = "Odata entity creation test";
 dab_BooksId = {};
 dab_BooksId.Id = author;
 dab_BooksId.LogicalName = "dab_author";
 dab_book.dab_BooksId = dab_BooksId;
 book = window.JSON.stringify(dab_book);

 createBook(book, url).done(process)

}

var createBook = function(book, url)
{
 return $.ajax({
 type:"POST", 
 contentType:"application/json;charset=utf-8",
 datatype:"json",
 data:book,
 url:url,
 beforeSend:function(x){x.setRequestHeader("Accept","application/json")},
 });
}

var process = function(data){
 var entity = data.d; 
 alert("Created new Book. Id:" + entity.dab_bookId);
}

Do bear in mind that casing is a bit funny. The relationship name is dab_booksid, however it needs to be sort of title cased to dab_BooksId, in essence the prefix needs to be kept in lower case, the rest Title Cased.

Also, jquery needs to be loaded if you are using Dynamics CRM 2011

Monday, 20 January 2014

Turn off IE Compatibility mode in MS Dynamics CRM 2011 or why indexOf doesn't work.

We'd been having navigation issues in MS Dynamics CRM 2011 for a while: Mouse scrolling wouldn't work and double clicking was necessary to select anything from a drop down menu. The issue would disappear if IE was using IE 9 document standards. The problem was that IE would "downgrade" itself to IE 7.

Somewhat bizarrely this wasn't occurring everywhere, it was just occurring in one of our environments causing loads of headaches for everybody. The testers were annoyed that they had, effectively limited functionality and kept forgetting to set document standards to IE 9 via developer tools. We weren't sure why this was happening in only one environment.

Things came to a head last week when I used a variation of my function getAllUserRoles and due to indexOf only being supported on IE > 9, it was working everywhere apart from on this environment. 

It turns out that there is a setting, introduced in UR12, called Load Pages in the most recent version of Internet Explorer, which modifies the headers so that the pages are rendered in the most recent version of IE.

Navigate to Settings -> Administration -> System Settings -> Customization.


Ticking this setting, will ensure that the default doc standards will be used and the heat death of the universe will have been staved off for another tick or two.

Monday, 13 January 2014

Get user's roles in MS Dynamics Crm 2011/2013

In MS Dynamics CRM 2011/13 there exists a JavaScript function to get the user's roles (Xrm.Page.context.getUserRoles) unfortunately, there are two problems with this function:
  1. It does not retrieve all roles, just those directly assigned to the user. In other words, if the user is a member of a team and that team has a role, this function will not find it.
  2. It returns the guids of the user roles rather than the names.

So in order to get around those shortcomings I wrote this function, which will return an array with all roles the user has including team roles. Note that this function is will only work in IE9+ as neither IE7 nor IE8 support indexOf, something that I will discuss in an upcoming post. It seems to work fine in Chrome (31) and Firefox (25).

function getAllUserRoles()
{
    var guid = "[A-z0-9]{8}-[A-z0-9]{4}-[A-z0-9]{4}-[A-z0-9]{4}-[A-z0-9]{12}";

    var serverUrl = Xrm.Page.context.getClientUrl();         
    var userId = Xrm.Page.context.getUserId();
    userId = userId.match(guid);
             
    var teamQuery = "TeamMembershipSet?$select=TeamId&$filter=SystemUserId eq guid'"+userId +"'";
    var teamRoleQuery = "TeamRolesSet?$select=RoleId&$filter=";
    var roleQuery = "RoleSet?$select=Name&$filter=";
    
    var teams = makeRequest(serverUrl,teamQuery,0);
    
    teamRoleQuery = composeQuery(teamRoleQuery,"TeamId",teams);
    var teamRoles = makeRequest(serverUrl,teamRoleQuery,1);

    userRoles = Xrm.Page.context.getUserRoles();
 
    if(userRoles != null){
     for(var i =0; i< userRoles.length;i++){
     teamRoles.push(userRoles[i].match(guid));
     }
    }

    roleQuery = composeQuery(roleQuery,"RoleId",teamRoles);
    var roles = makeRequest(serverUrl,roleQuery,2);
    
    return roles;
}

function makeRequest(serverUrl, query, type)
{

    var oDataEndpointUrl = serverUrl + "/XRMServices/2011/OrganizationData.svc/";
    oDataEndpointUrl += query;

    var service = GetRequestObject();

    if (service != null)
    {

        service.open("GET", oDataEndpointUrl, false);
        service.setRequestHeader("X-Requested-With", "XMLHttpRequest");
        service.setRequestHeader("Accept", "application/json, text/javascript, */*");
        service.send(null);

        var retrieved = $.parseJSON(service.responseText).d;

        var results =  new Array();
                               
        switch (type)
        {

        case 0:
        for (var i=0; i < retrieved.results.length;i++){
          results.push(retrieved.results[i].TeamId);
          }
          break;
        case 1:
        for (var i=0; i < retrieved.results.length;i++){
          results.push(retrieved.results[i].RoleId);
          }
          break;

        case 2:
        for (var i=0; i < retrieved.results.length;i++){
          if(results.indexOf(retrieved.results[i].Name)==-1){
           results.push(retrieved.results[i].Name);
           }
          }
          break;
         }                                     
        return results;
     }
return null;
}

function GetRequestObject()
{

    if (window.XMLHttpRequest)
    {
        return new window.XMLHttpRequest;
    }
    else
    {
        try
        {
            return new ActiveXObject("MSXML2.XMLHTTP.3.0");
        }
        catch (ex)
        {
            return null;
        }
    }
}

function composeQuery (queryBase, attribute, items )
{
 if (items != null){
     for(var i=0; i < items.length; i++){
      if (i==0)
      {
       queryBase += attribute + " eq (guid'"+items[i]+"')";
      }
      else
      {
       queryBase += " or " + attribute + " eq (guid'"+items[i]+"')";
      }
     }
    }
 return queryBase;
}

 
I think one of these days I will get the hang of JavaScript but I still find it really obnoxious to work with.

Monday, 27 May 2013

Set Activities filter on contact's entity form to All on MS Dynamics CRM 2011

The default filter for the activities lookup view on the contact form is Next 30 days, which is something that I was asked to change, so this is what I did.

The SetView function was registered on the onload event of the contact form and a parameter of 'All' was passed to set the view

function SetView(Value)
{
   SetDefaultView = function (viewCombo, viewName, appGrid)
   {
      if (viewCombo.value != viewName)
      {
         viewCombo.value = viewName;
      }
   }
/*I don't think this is actually needed, too lazy to check */
   areaActivitiesFrame_OnReadyStateChange = function ()
   {
      if (this.readyState == "complete")
      {
         var frame = getiFrame("areaActivitiesFrame");
         var viewCombo = frame.contentWindow.document.getElementById("crmGrid_Contact_ActivityPointers_datefilter");
         var appGrid = frame.contentWindow.document.getElementById("AppGridFilterContainer");
         if (viewCombo.readyState == "complete")
         {
            SetDefaultView(viewCombo, defaultValue, appGrid);
         }
         else
         {
            viewCombo.onreadystatechange = function ()
            {
               if (this.readyState == "complete")
               {
                  SetDefaultView(this, defaultValue, appGrid);
               }
            }
         }
      }
   }

   if (document.getElementById(navActivities) != null)
   {
      document.getElementById(navActivities).onclick = function ()
      {
         loadArea(this,"areaActivities");
         var iframe =  getiFrame(areaActivitiesFrame);

         iframe.onreadystatechange = function ()
         {
            if (this.readyState == "complete")
            {
               var frame = getiFrame("areaActivitiesFrame");
               var viewCombo = frame.contentWindow.document.getElementById("crmGrid_Contact_ActivityPointers_datefilter");               
               var appGrid = frame.contentWindow.document.getElementById("AppGridFilterContainer");
               if (viewCombo.readyState == "complete")
               {
                  SetDefaultView(viewCombo, defaultValue, appGrid);
               }
               else
               {
                viewCombo.onreadystatechange = function ()
                {
                   if (this.readyState == "complete")
                   {
                      SetDefaultView(this, defaultValue, appGrid);
                   }
                }
               }

            }
         }
      }
   }
}

function getiFrame(iframeName)
{
 var frames=document.getElementsByTagName('iframe');

  for(var i =0 ; i < frames.length;i++)
  {
    if (frames[i].name == iframeName)
     {
      var theFrame = frames[i];
     }
  }
 return theFrame;
}