getEnumerator завершается с ошибкой коллекции, не инициализированной

Я использую JSOM для поиска значения в определенном поле определенного элемента в определенном списке. В целом код ищет членство пользователя в группе (используя SPServices), затем использует это значение для сопоставления с элементом в списке (список содержит поле «Название», заполненное именами групп, и поле «Портал», содержащее другую строку) и пытается чтобы получить другое значение из этого элемента списка. Ошибка, которую я получаю, находится в строке 'var listItemEnumerator = this.listItems.getEnumerator();'. Ошибка: «Коллекция не была инициализирована. Она не запрашивалась или запрос не был выполнен. Возможно, ее необходимо запросить явно».

Вот код:

function getPortalURL(userGroup) {
     var URL = "";

     var ctx = new SP.ClientContext.get_current();
     var list = ctx.get_web().get_lists().getByTitle('Clients');

     var query = "<View><Query><Where><Eq><FieldRef Name='Title'><Value Type='Text'>" + userGroup + "</Value></Eq></Where></Query></View>";
     var camlQuery = new SP.CamlQuery();
     camlQuery.set_viewXml(query);

     this.listItems = list.getItems(camlQuery);
     ctx.load(this.listItems);
     ctx.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded(URL)), Function.createDelegate(this, this.onQueryFailed));

     return URL;
}
function onQuerySucceeded(URL) {
    var listItemEnumerator = this.listItems.getEnumerator();

    while (listItemEnumerator.moveNext()) {
        var currentItem = listItemEnumerator.get_current();

        URL = currentItem.get_item('Portal');
    }
}
function onQueryFailed(sender, args) {
    alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}

РЕДАКТИРОВАТЬ: я обновил свой код, чтобы отразить приведенные ниже изменения, но теперь я вижу, что запрос терпит неудачу при каждой попытке, всегда перенаправляясь к функции отказа. Вот код на случай, если я сделал что-то не так в своей реализации:

function getPortalURL(userGroup) {
    var query = "<View><Query><Where><Eq><FieldRef Name='Title'><Value Type='Text'>" + userGroup + "</Value></Eq></Where></Query></View>";

    getListItems('Clients', query,
        function(items) {
            if(items.get_count() === 1) {
                var item = items.getItemAtIndex(0);
                alert(item.get_item('Portal'));
            }
        },
        function(sender,args){
            alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
        }
    );
}

function getListItems(listTitle, queryText, success, error) {
    var ctx = SP.ClientContext.get_current();
    var web = ctx.get_web();
    var list = web.get_lists().getByTitle(listTitle);
    var query = new SP.CamlQuery();
    query.set_viewXml(queryText);
    var items = list.getItems(query);
    ctx.load(items);
    ctx.executeQueryAsync(
      function() {
          success(items);
      },
      error
    );
}

person Daniel Charlton    schedule 08.10.2014    source источник


Ответы (1)


Некоторые исправления (ошибка возникает, вероятно, из-за 3-го пункта):

  • var ctx = SP.ClientContext.get_current(); //since new constructor is not needed
  • Оператор return необходимо удалить, так как SP.ClientContext.executeQueryAsync является асинхронным методом.
  • замените ctx.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded(URL)), Function.createDelegate(this, this.onQueryFailed)); на ctx.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded), Function.createDelegate(this, this.onQueryFailed));, так как SP.ClientContext.executeQueryAsync принимает функции обратного вызова

Вместо этого я бы рекомендовал использовать следующий общий метод. Это позволяет загружать элементы списка, указав List Title и CAML query:

function getListItems(listTitle,queryText, success,error){
    var ctx = SP.ClientContext.get_current();
    var web = ctx.get_web();
    var list = web.get_lists().getByTitle(listTitle);
    var query = new SP.CamlQuery();
    query.set_viewXml(queryText);
    var items = list.getItems(query);
    ctx.load(items);
    ctx.executeQueryAsync(
      function() {
          success(items);
      },
      error
    );
}

Использование

Загрузите элементы списка из списка страниц и распечатайте первый:

getListItems('Pages','<View><Query/></View>',
   function(items){
       if(items.get_count() > 0) {
           var firstItem = items.getItemAtIndex(0);
           console.log(firstItem.get_item('Title'));
       }   
   },
   function(sender,args){
      console.log(args.get_message());
   }
);    

В вашем случае, поскольку необходимо найти конкретный элемент, можно использовать следующий пример:

getListItems('<List Title>','<Your query goes here>',
   function(items){
       if(items.get_count() === 1) {  //Is item found?
           var item = items.getItemAtIndex(0);
           console.log(item.get_item('<Field Name>'));
       }       
   },
   function(sender,args){
      console.log(args.get_message());
   }
);    

Обновить

В запросе опечатка, исправлен запрос:

<View><Query><Where><Eq><FieldRef Name='Title'/><Value Type='Text'>" + userGroup + "</Value></Eq></Where></Query></View>
person Vadim Gremyachev    schedule 08.10.2014
comment
Спасибо за предложение. Я попытался реализовать это, но теперь мой запрос направляется к функции отказа при каждой попытке. Я отредактировал свой OP, чтобы добавить новый код (для него недостаточно места в комментариях) на случай, если я сделал что-то не так в реализации. - person Daniel Charlton; 09.10.2014
comment
Ваша обновленная версия выглядит намного лучше, эта ошибка возникает из-за опечатки в запросе, см. обновленный ответ :) - person Vadim Gremyachev; 09.10.2014
comment
Клянусь, по крайней мере 90% моих ошибок в коде — опечатки. Большое спасибо за помощь. (Я бы проголосовал, но я недостаточно авторитетен.) - person Daniel Charlton; 09.10.2014