You may have seen me tweet about roboCAML the last few days. If you were scratching your head about what it actually is, don’t feel bad. No one knew… It’s a jQuery module, *not* a plugin, I’ve built specifically to handle the tedious task of manually building CAML or worse hard coding CAML
within your scripts. An added benefit, is the ability to create dynamic CAML queries on the fly.
Currently roboCAML has a depends on jQuery, but very well may become a pure JavaScript module without any external dependencies. It's hard to beat the $.ajax function within jQuery, but I'm willing to change based on feedback. It’s all about the community, you know?
What does it do?
roboCAML takes away the pain of scripts that look like this:
// #CAMLToggle doesn't exist, but this is here in case we want to give the user the ability to AND
// or OR the PartNum
var camlToggle = $("#CAMLToggle").val() ? $("#CAMLToggle").val() : "Or",
ddlSelected = false,
PartCat = [],
PartNum = [],
thisFieldRef = "",
camlQuery = "";
$( "select.PartCat" ).each(function() {
// Each select on the page has the PartCat class
// the title attribute is also the name of the field for the CAML
ctlTitle = $(this).attr("title");
PartCat[ctlTitle] = ctlTitle;
if ( ctlTitle ) != 0 ) {
ddlSelected = true;
}
});
//First example of CAML engine
i = 0;
for (index in PartCat) {
//console.log("Select title: " + i);
//console.log("Select Val: " + PartCat[i]);
if (PartCat[index] > 0) {
thisFieldRef = "<Eq><FieldRef Name='" + index + "' LookupId='True' /><Value Type='Number'>" + PartCat[index] + "</Value></Eq>";
if (i <= 1) {
camlQuery += thisFieldRef;
}
if (i == 1) {
camlQuery = "<And>" + camlQuery + "</And>";
}
if (i > 1) {
camlQuery = "<And>" + camlQuery + thisFieldRef + "</And>";
}
i++;
}
}
//Show example of other CAML Engine
$("input.PartNum:checked").each(function(index) {
// If this isn't the first PartNum, we'll "wrap" the array with the camlToggle
if(index > 0) {
PartNum.unshift("<" + camlToggle + ">");
}
PartNum.push("<Eq><FieldRef Name='PartNum' LookupId='True' /><Value Type='Number'>" + $(this).attr("alt") + "</Value></Eq>");
// If this isn't the first PartNum, we'll "wrap" the array with the camlToggle
if(index > 0) {
PartNum.push("</" + camlToggle + ">");
}
});
// .join() defaults to commas, .join("") does the same thing. We'll join with a space, then replace
// the spaces that fall between tags
camlQuery += PartNum.join(" ").replace(/> </gi,"><");
if ( $("input.PartNum:checked").length > 0 && ddlSelected ) {
// If we have DDLs and PartNums, we'll <And> the two groups together, otherwise we won't
camlQuery = "<And>" + camlQuery + "</And>";
}
camlQuery = "<Query><Where>" + camlQuery + "</Where><OrderBy><FieldRef Name='Title' Ascending='True' /></OrderBy></Query>";
GetListItems(camlQuery);
}
Within this script are two different ways to dynamically build CAML. Each have their merits, but why do I have to think about setting up my CAML correctly and debugging it if I am having issues? After being tasked to build a few of the complex scripts, sometimes several in a week, I had enough... Time to roll up the sleeves and code a solution. This is why I’ve built roboCAML, so now lets see what it does.
roboCAML In Action
roboCAML will assist in generating a string of useful CAML for use when making your Web Service or Client Object Model calls. There are currently 5 methods available in roboCAML.
roboCAML.BatchCMD
So, now let’s look at roboCAML.BatchCMD method. This method is a little tricky because there are three distinct actions you can take when using a batch. Each requiring a different set of parameters. In example 2.1, we’ll look at Deleting:
Example 2.1:
roboCAML.BatchCMD({
batchCMD: 'Delete',
IDs: [1,2,3]
});
This call accepts an array of ID’s and the “Delete” command. The output will be:
<Batch OnError='Continue'><Method ID='3' Cmd='Delete'><Field Name='ID'>3</Field></Method><Method ID='2' Cmd='Delete'><Field Name='ID'>2</Field></Method><Method ID='1' Cmd='Delete'><Field Name='ID'>1</Field></Method></Batch>
Now onto the New operation. This example accepts the command for the batch. What is different here from the Delete operation is, we can now pass in a valuePairs parameter. This parameter accepts an array of arrays. You’ll notice each array follows a certain pattern. First the Static Name is provided and then the value.
Example: 2.2:
roboCAML.BatchCMD({
batchCMD: "New",
valuePairs: [["PersonnelLookup", 1]] //Static Column Name, Value
});
A more complex array would look like this:
roboCAML.BatchCMD({
batchCMD: "New",
valuePairs: [["PersonnelLookup", 1, "ModuleNotes", "ModuleNotes", "Description", "Googly Glop"], ["ListUID", 3]] //Static Column Name, Value
});
Which in turn produces:
<Batch OnError='Continue'><Method ID='1' Cmd='New'><Field Name='PersonnelLookup'>1</Field><Field Name='ModuleNotes'>ModuleNotes</Field><Field Name='Description'>Googly Glop</Field></Method><Method ID='2' Cmd='New'><Field Name='ListUID'>3</Field></Method></Batch>
The last operation within roboCAML.BatchCMD is Update:
Example 2.3
roboCAML.BatchCMD({
updates: [
{
//Notice batchCMD isn't present...
//Static Column Name, Value
valuePairs: ["Title", "Numero Tres", "PercentComplete", 1, "Boolean", 0, "ID", 3]
},
{
//Defaults to Update anyway. No need to pass it.
batchCMD: "Update",
valuePairs: ["ID", 4, "Title", "Item4", "Boolean", 0]
},
{
batchCMD: "New",
valuePairs: ["Title", "Something New", "PercentComplete", 1]
},
{
batchCMD: "Delete",
ID: 6
}
]
});
The output of the call above will generate:
<Batch OnError='Continue'>
<Method ID='1' Cmd='Update'>
<Field Name='Title'>Numero Tres</Field>
<Field Name='PercentComplete'>1</Field>
<Field Name='Boolean'>0</Field>
<Field Name='ID'>3</Field>
</Method>
<Method ID='2' Cmd='Update'>
<Field Name='ID'>4</Field>
<Field Name='Title'>Item4</Field>
<Field Name='Boolean'>0</Field>
</Method>
<Method ID='3' Cmd='New'>
<Field Name='Title'>Something New</Field>
<Field Name='PercentComplete'>1</Field>
</Method>
<Method ID='4' Cmd='Delete'>
<Field Name='ID'>6</Field>
</Method>
</Batch>
What’s
very interesting with using the updates property of roboCAML.BatchCMD is the batch that is generated can be chocked full of all your different operations. Delete, New and Update all within one Web Service call. That’s #bada55.
roboCAML.OrderBy
And if you weren’t impressed by any of the above, maybe this
will persuade you… It’s another snazzy way to build CAML on the fly. Here’s how
to use roboCAML.OrderBy:
.