Good Framework to handle Caml in SPFx

Good Framework to handle Caml in SPFx

I usually use PnP JS to make my calls in a SPFx Webpart, this is a great framework, you can expand lookup fields simple and clean. The problem is you cannot use Project Fields in order to query 2 levels, let’s start with an example:

 sp.web.lists.getByTitle("WorkshopResult")
.items.select("Participant/Id, Workshop/Title, Workshop/Date1")
.expand("Workshop", "Participant")
.filter("Participant/Id eq '" + id + "'") 
.top(5000)

In this case you are expanding Title from Workshop and Id from Participant, what about if Workshop have a relation with a City List? in this case you have to use projected fields to query a List from another List

Projected Fields

From Microsoft, an example

<ProjectedFields>
  <Field
    Name='CustomerCity'
    Type='Lookup'
    List='customerCities'
    ShowField='Title' />
</ProjectedFields>

I’m exploring a framework CamlJS from Andrei Markeev in order to smooth the user experience in TypeScript in a ReactJs WebPart. This framework was originally developed for JavaScript, so I ended up with some problems.

First the result of the Caml Query add a perfix to the Object as you can see here

{$o_1: true, $N_1: '<View><ViewFields><FieldRef Name="WorkShop" /><FieldRef Name="Participant" /></ViewFields></View>'}
$N_1: "<View><ViewFields><FieldRef Name=\"WorkShop\" /><FieldRef Name=\"Participant\" /></ViewFields></View>"
$o_1: true

$N_1 is the View and $o_1 is a boolean value, so what can I do since this is not a valid Caml Object in SPFx?

Let’s run this Sample

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

Result

<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>

In order the values can be readable in the PnP JS Framework, I had to do this

//Query
var query = new CamlBuilder()
          .View(["WorkShop", "Participant"])
          .ToCamlQuery();

//Convert to String
let camlQuery = JSON.stringify(query);
console.log(query);

//Add extra escapes
let regexp = new RegExp(camlQuery);

//Remove invalid data
let cq = camlQuery.replace('"$o_1":true,"$N_1":"', '').substring(1).slice(0, -2);

//Define the ViewXML
var q = {
  ViewXml:
  cq
};

Now we have a valid Query Object tu use in PnP JS

{ViewXml: '<View><ViewFields><FieldRef Name=\"WorkShop\" />
<F…ldRef Name=\"Participant\" /></ViewFields></View>'}
ViewXml: "<View><ViewFields><FieldRef Name=\\\"WorkShop\\\" /><FieldRef Name=\\\"Participant\\\" /></ViewFields></View>"
[[Prototype]]: Object

Use like This

sp.web.lists.getByTitle("WorkshopResult")
            .getItemsByCAMLQuery(q)
            .then(items => {
              console.log(items);

Leave a Reply

Your email address will not be published. Required fields are marked *

RSS