0

Like the title says I want to retrieve the contenttype name of list items with Javascript. to be concrete: User opens the "new form" in list a and with Javascript and CSR there should be an alert of the content type name of list items in list b. To do this I tried the following:

var collListItem = null;
var contentobject = null;
var ctx = null;
var oList = null;
SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
  OnPostRender: function() { 
  $(document).ready( function() {ExecuteOrDelayUntilScriptLoaded(loadConstants, "sp.js")});
  }
});
function loadConstants() {
ctx = new SP.ClientContext.get_current();
var web = ctx.get_web();
ctx.load(web);
var listcol = web.get_lists();
ctx.load(listcol);
var oList = listcol.getByTitle('Aktionslisten');
var camlQuery = new SP.CamlQuery();
   camlQuery.set_viewXml('<View><Query><Where><Geq><FieldRef Name=\'ID\'/><Value Type=\'Number\'>1</Value></Geq></Where></Query></View>');
collListItem = oList.getItems(camlQuery);
   ctx.load(collListItem);
ctx.executeQueryAsync(Function.createDelegate(this, this.onSuccess), Function.createDelegate(this, this.onFail));
}

function onSuccess(sender, args) {
   var listInfo = '';
    var listEnumerator = collListItem.getEnumerator();
    while (listEnumerator.moveNext()){
        oList = listEnumerator.get_current();
        var ID = oList.get_id();
        contentobject = oList.get_contentType();
        ctx.load(contentobject);
        ctx.executeQueryAsync(function(){
            var value = contentobject.get_name();
            alert("VAL: "+value);
        },function(){alert("No Success");});


    }
}

function onFail(sender, args) {
    console.log("Errorlog: "+ args.get_message());
}

But this code just gives me the content type of the last item a few times. I think I'm maybe doing something wrong with the "executeQuery" function?

Best regards, André

Update (see comments below)

The new try for the code, which is also not working:

var collListItem = null;
var ctx = null;
var oList = null;
SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
  OnPostRender: function() { 
  $(document).ready( function() {ExecuteOrDelayUntilScriptLoaded(loadConstants, "sp.js")});
  }
});
function loadConstants() {
ctx = new SP.ClientContext.get_current();
var web = ctx.get_web();
ctx.load(web);
var listcol = web.get_lists();
ctx.load(listcol);
var oList = listcol.getByTitle('Aktionslisten');
var camlQuery = new SP.CamlQuery();
   camlQuery.set_viewXml('<View><Query><Where><Geq><FieldRef Name=\'ID\'/><Value Type=\'Number\'>1</Value></Geq></Where></Query></View>');
collListItem = oList.getItems(camlQuery);
   ctx.load(collListItem);
ctx.executeQueryAsync(Function.createDelegate(this, this.onSuccess), Function.createDelegate(this, this.onFail));
}

function onSuccess(sender, args) {
   var listInfo = '';
    var listEnumerator = collListItem.getEnumerator();
    while (listEnumerator.moveNext()){
        oList = listEnumerator.get_current();
        getcontenttypetitle(oList.get_contentType(), ctx);
    }
}

function onFail(sender, args) {
    console.log("Errorlog: "+ args.get_message());
}

function getcontenttypetitle(contentobject,clientContext){
    this.object = contentobject;
    clientContext.load(object);
    clientContext.executeQueryAsync(Function.createDelegate(this, this.onSuccess2), Function.createDelegate(this,this.onFail2));
}

function onSuccess2 (sender,args){
 alert("VAL: "+ this.object.get_name());
}

function onFail2(sender,args){
    alert("fail");
}

//$(":input[title='Aktionsliste']").find('option:contains(Teammeetings)').remove();
Aquen
  • 7
  • 1
  • 4
  • The reason why it alerts the same thing multiple times is because when your callback to `executeQueryAsync` is executed, any variables in the closure refer to the actual variables in that scope. That is, a closure captures the *variable* `contentobject`, not its current value when you call `executeQueryAsync`. Since it refers to the variable, its callback value is the value at the end of the loop. To fix it, you need to create a separate closure for each `contentobject`. To see how that's done, read this answer on a question about this problem: http://stackoverflow.com/a/19324832/2407870 – Chris Middleton Feb 24 '16 at 09:07
  • Hi, thank you for your fast answer. I read the article and made a new try which has the same error again sadly. I've posted the new Code at the end of my question. What I thought/tried: I created a new function "getcontenttypetitle". This function gets the current contentType of the list item and the clientContext. I thought this would solve the problem since I give it the current contenttype and not the last? I suppose the problem is still there because of "this." But if I don't use this keyword then how can I access the variable in "onSuccess2"? – Aquen Feb 24 '16 at 10:51

1 Answers1

0

The reason why it alerts the same thing multiple times is because when your callback to executeQueryAsync is executed, any variables in the closure refer to the actual variables in that scope. That is, a closure captures the variable contentobject, not its current value when you call executeQueryAsync. Since it refers to the variable, its callback value is the value at the end of the loop. To fix it, you need to create a separate closure for each contentobject. To see how that's done, read this answer on a question about this problem: https://stackoverflow.com/a/19324832/2407870.

You were closer with your earlier revision. Here is the part from your first version that you need to change. (Note the comment in the code.)

while (listEnumerator.moveNext()){
    oList = listEnumerator.get_current();
    var ID = oList.get_id();
    contentobject = oList.get_contentType();
    ctx.load(contentobject);
    ctx.executeQueryAsync(
        // !! Here we use an IIFE (immediately invoked function expression)
        // to create a new callback each time through the loop.
        // We pass in the contentobject into our IIFE,
        // which causes the closure to be around the variable 
        // inside the scope of our IIFE,
        // instead of inside the scope of the function containing the while loop.
        (function (contentobject) {
            return function () {
                var value = contentobject.get_name();
                alert("VAL: "+value);
            };
        }(contentobject)),
        function () {
            alert("No Success");
        }
    );
}
Community
  • 1
  • 1
Chris Middleton
  • 5,654
  • 5
  • 31
  • 68