Skip to content
master
Go to file
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
lib
 
 
 
 
 
 
 
 
 
 
 
 

README.md

Installation

Nuget:

PM> Install-Package CamlJs

Nuget TypeScript definitions:

PM> Install-Package camljs.TypeScript.DefinitelyTyped

Npm:

npm install camljs

Npm TypeScript definitions:

npm install @types/camljs

Also check out CamlJs Console - Chrome extension for testing queries with live preview against real lists.

Usage

In browser:

<script type="text/javascript" src="//unpkg.com/camljs"></script>
<script>
    alert(new CamlBuilder().View().ToString());
</script>

In node:

var CamlBuilder = require('camljs');
console.log(new CamlBuilder().View().ToString());

ES2015 modules:

import * as CamlBuilder from 'camljs';
console.log(new CamlBuilder().View().ToString());

Basics

Let's assume we need to fetch all Google-related emails from a SharePoint list where your company stores archived project emails. To generate the corresponding query using CamlJs, you could use following javascript code:

var camlBuilder = new CamlBuilder();

var caml = camlBuilder.Where()
    .TextField("Email").EqualTo("support@google.com")
    .Or()
    .TextField("Email").EqualTo("plus@google.com")
    .Or()
    .TextField("Title").BeginsWith("[Google]")
    .Or()
    .TextField("Content").Contains("Google")
    .ToString();

This will generate the following CAML code:

<Where>
  <Or>
    <Eq>
      <FieldRef Name="Email" />
      <Value Type="Text">support@google.com</Value>
    </Eq>
    <Or>
      <Eq>
        <FieldRef Name="Email" />
        <Value Type="Text">plus@google.com</Value>
      </Eq>
      <Or>
        <BeginsWith>
          <FieldRef Name="Title" />
          <Value Type="Text">[Google]</Value>
        </BeginsWith>
        <Contains>
          <FieldRef Name="Content" />
          <Value Type="Text">Google</Value>
        </Contains>
      </Or>
    </Or>
  </Or>
</Where>

It is also possible to generate SP.CamlQuery object, just change .ToString() to .ToCamlQuery().

Another example:

var caml = camlBuilder.Where()
    .LookupField("Category").Id().In([2, 3, 10])
    .And()
    .DateField("ExpirationDate").LessThanOrEqualTo(CamlBuilder.CamlValues.Now)
    .OrderByDesc("ExpirationDate")
    .ToString()

As you see, the code is pretty clean and readable. The resulting CAML is much more awkward, especially if you imagine it in javascript strings dress, without indentation and highlighting...

<Where>
  <And>
    <In>
      <FieldRef Name="Category" LookupId="TRUE" />
      <Values>
        <Value Type="Integer">2</Value>
        <Value Type="Integer">3</Value>
        <Value Type="Integer">10</Value>
      </Values>
    </In>
    <Leq>
      <FieldRef Name="ExpirationDate" />
      <Value Type="Date">
        <Now />
      </Value>
    </Leq>
  </And>
</Where><OrderBy>
  <FieldRef Name="ExpirationDate" Ascending="FALSE" />
</OrderBy>

Dynamic queries

It's very easy to create dynamic queries with CamlJs by leveraging the CamlBuilder.Expression() construction. It's like a standalone part of query that can be later used in the final new CamlBuilder.Where() or new CamlBuilder.View().

var categories = ["Category 1", "Category 2", "Category 3"];

var categoriesExpressions = categories.map(c => CamlBuilder.Expression().TextField("Category").EqualTo(c));

var caml = new CamlBuilder().Where()
    .Any(categoriesExpressions),
    .ToString();

Result:

<Where>
    <Or>
        <Eq>
            <FieldRef Name="Category" />
            <Value Type="Text">Category 1</Value>
        </Eq>
        <Or>
            <Eq>
                <FieldRef Name="Category" />
                <Value Type="Text">Category 2</Value>
            </Eq>
            <Eq>
                <FieldRef Name="Category" />
                <Value Type="Text">Category 3</Value>
            </Eq>
        </Or>
    </Or>
</Where>

While .Any() generates <Or> clauses, .All() will generate <And>.

Elements support

CamlJs supports all Query elements that are described on MSDN.

For example, seldom used Membership element:

var caml = camlBuilder.Where()
    .UserField("AssignedTo").EqualToCurrentUser()
    .Or()
    .UserField("AssignedTo").IsInCurrentUserGroups()
    .GroupBy("ProductTitle")
    .OrderBy("Priority").ThenBy("Title")
    .ToString();

This code will generate following CAML:

<Where>
  <Or>
    <Eq>
      <FieldRef Name="AssignedTo" />
      <Value Type="Integer">
        <UserID />
      </Value>
    </Eq>
    <Membership Type="CurrentUserGroups">
      <FieldRef Name="AssignedTo" />
    </Membership>
  </Or>
</Where>
<GroupBy>
  <FieldRef Name="ProductTitle" />
</GroupBy>
<OrderBy>
  <FieldRef Name="Priority" />
  <FieldRef Name="Title" />
</OrderBy>

You can also create the upper-level View element as supported by SP.CamlQuery object. Scope attribute, ViewFields, Joins and ProjectedFields are supported in this case.

Joining lists via CamlJs is very easy. Here's the example:

var query = new CamlBuilder()
    .View(["Title","Country","Population"])
    .LeftJoin("Country","Country").Select("People","Population")
    .Query()
    .Where()
    .NumberField("Population").LessThan(10)
    .ToString();

The resulting generated CAML query will be the following:

<View>
    <ViewFields>
        <FieldRef Name="Title" />
        <FieldRef Name="Country" />
        <FieldRef Name="Population" />
    </ViewFields>
    <Joins>
        <Join Type="LEFT" ListAlias="Country">
            <Eq>
                <FieldRef Name="Country" RefType="ID" />
                <FieldRef Name="ID" List="Country" />
            </Eq>
        </Join>
    </Joins>
    <ProjectedFields>
        <Field ShowField="People" Type="Lookup" Name="Population" List="Country" />
    </ProjectedFields>
    <Query>
        <Where>
            <Lt>
                <FieldRef Name="Population" />
                <Value Type="Number">10</Value>
            </Lt>
        </Where>
    </Query>
</View>

Modify existing queries

Often you need to modify existing query (e.g. that comes from an existing list view), rather than generate a completely new one. This use case is also supported by CamlJs:

  • CamlBuilder.FromXml(xml) method will create a CamlBuilder object from existing CAML string
  • ReplaceWhere method then allows to replace clause with one generated by CamlJs
  • ModifyWhere().AppendAnd() will add new conditions to existing query using "And" operator
  • ModifyWhere().AppendOr() will add new conditions to existing query using "Or" operator

Example:

var xml = new CamlBuilder().View().Query().Where()
    .UserField("Author").EqualToCurrentUser()
    .ToString();

var query = CamlBuilder.FromXml(xml)
    .ModifyWhere().AppendAnd()
    .LookupField("Country").ValueAsText().BeginsWith("G");

Result:

<View>
  <Query>
    <Where>
      <And>
        <Eq>
          <FieldRef Name="Author" LookupId="TRUE" />
          <Value Type="Integer">
            <UserID />
          </Value>
        </Eq>
        <BeginsWith>
          <FieldRef Name="Country" />
          <Value Type="Text">G</Value>
        </BeginsWith>
      </And>
    </Where>
  </Query>
</View>
You can’t perform that action at this time.