1

The following function has a currentBillCyclePath parameter which I need to use to filter out some of the elements I received after the query is executed. The problem is that

inside the while, that value is not present anymore its undefined. But when the method starts the value is there.

Basically I need to get: listItemValues.FileRef.split("/")[4]; and if it matches the currentBillCyclePath, then I dont add it to the array.

function GetRelatedBillingDocumentsFromList(selectProperties, currentBillCyclePath, clientCode, jobCodes, engagementCode, enhanceFunctions) {
            $log.info("Retrieving related billing documents for bill cycle with name [" + currentBillCyclePath + "]");                  
            var deferred = $q.defer();
            var webUrl = _spPageContextInfo.webAbsoluteUrl;

            selectProperties = selectProperties.concat("ContentTypeId");
            var viewFields = spService.ConvertSelectPropertiesToViewFields(selectProperties);
            // query must return the documents for the same client but in other bill cycles not the current one
            var camlQuery = '<View Scope="RecursiveAll">' +   viewFields + 
                    '<Query>' +
                        '<Where>' +
                            '<And>' +
                                '<Eq>' +
                                    '<FieldRef Name="ClientCode" />' +
                                    '<Value Type="Text">'+ clientCode + '</Value>' +
                                '</Eq>' +
                                '<Neq>' +
                                    '<FieldRef Name="ContentType" />' +
                                    '<Value Type="Computed">Bill Cycle</Value>' +
                                '</Neq>' +
                            '</And>' +
                        '</Where>' +
                    '</Query>' +
                '</View>';

            var billCyclesListId = "{c23bbae4-34f7-494c-8f67-acece3ba60da}";                    
            spService.GetListItems(billCyclesListId, camlQuery, selectProperties)
            .then(function(listItems) {                 
                var listItemsWithValues = [];

                if(listItems) {
                    var enumerator = listItems.getEnumerator();
                    var promises = [];
                    while (enumerator.moveNext()) {
                        var listItem = enumerator.get_current();
                        var listItemValues = [];                                
                        selectProperties
                        .forEach(function(propertyName) {                               
                            var value = listItem.get_item(propertyName);
                            if(propertyName === "JobCodesMulti"){
                                jobvalue = "";
                                value.forEach(function(jobvalues){
                                    jobvalue+= jobvalues.get_lookupValue() +";";
                                })
                                listItemValues[propertyName] = jobvalue;
                            }else{
                                listItemValues[propertyName] = value;
                            }   
                        });

                        listItemsWithValues.push(listItemValues);
                    }

                    var promises = listItemsWithValues.map(addContentType);
                    $q.all(promises).then(youCanUseTheData);

                    function youCanUseTheData(){
                        /*
                        At this point, each listItem holds the 'Document Type' info
                        */
                        listItemsWithValues.forEach(function(listItem) {
                            var fileDirRef = listItem["FileRef"];
                            var id = listItem["ID"];
                            var title = listItem["Title"];
                            var serverUrl = _spPageContextInfo.webAbsoluteUrl.replace(_spPageContextInfo.webServerRelativeUrl,"");                          
                            var dispFormUrl = serverUrl + "/sites/billing/_layouts/15/DocSetHome.aspx?id="+fileDirRef;
                            var parentLink = listItem["FileRef"];
                            arrayofstrings = parentLink.split("/");
                            var billCycleFolderName = arrayofstrings[arrayofstrings.length-2];
                            arrayofstrings.pop();
                            var hyperLink = '<a href="' + arrayofstrings.join('/') + '">' + billCycleFolderName + '</a>';                           
                            listItem["Bill Cycle"] = hyperLink; 
                            listItemsWithValues["Document Type"] = getContentTypeOfCurrentItem(listItem.ID.toString());
                        });

                        var enhancedListItemValues = spService.SpSearchQuery.EnhanceSearchResults(listItemsWithValues, enhanceFunctions);                       
                        deferred.resolve(listItemsWithValues);
                    }
                }   

            })
            .catch (function (message) {
                deferred.reject();
            });

            return deferred.promise;
        }

Update: Syntax error enter image description here

Update 2: Added GetData function

function GetData(billCyclePath, clientCode, jobCodes, engagementCode) {             
                var enhanceFunctions = [
                    function(searchResultRow) {
                        return spService.AddHyperLinkOnFields(searchResultRow, config.HyperLinks);
                    },
                    function(searchResultRow) {
                        return spService.AddPresenceOnFields(searchResultRow, config.UserFields);
                    },
                    function(searchResultRow) {
                        return spService.FormatDateFields(searchResultRow, config.DateFields, generalConfig.DateTimeFormat);
                    },
                    function(searchResultRow) {
                        return spService.AddImageMapping(searchResultRow, config.ImageFields);
                    },
                    function(searchResultRow) {
                        return spService.FormatNumberFields(searchResultRow, config.NumberFields);
                    },
                    function(searchResultRow) {
                        // Put link to parent Bill Cycle with name = folder name
                        //var parentLink = searchResultRow["FileRef"];
                        //arrayofstrings = parentLink.split("/");
                        //var billCycleFolderName = arrayofstrings[arrayofstrings.length-2];
                        //arrayofstrings.pop();
                        //var hyperLink = '<a href="' + arrayofstrings.join('/') + '">' + billCycleFolderName + '</a>';                         
                        //searchResultRow["Bill Cycle"] = hyperLink; 
                    }
                ];

                // Get data from SP             
                var selectProperties = spService.TransformFieldsToSelectProperties(config.Fields); // copy array
                var selectPropertiesToShow = spService.TransformFieldsToSelectProperties(config.FieldsToShow); // copy array

                var extendedSelectProperties = selectProperties.slice();
                var hyperLinkedProperties = spService.TransformFieldsToSelectProperties(config.HyperLinks)
                extendedSelectProperties = extendedSelectProperties.concat(hyperLinkedProperties);

                GetRelatedBillingDocumentsFromList(extendedSelectProperties, billCyclePath, clientCode, jobCodes, engagementCode, enhanceFunctions)
                .then(function (data) {
                    var trimmedData = spService.SpSearchQuery.TrimSearchResultsToSelectProperties(data, selectPropertiesToShow);
                    // Add data to dataTable
                    var dataTable = $(tableSelector).DataTable();
                    dataTable.clear().rows.add(trimmedData).columns.adjust().draw(); // Resize columns based on new data sizes                                          
                    vm.ValidDataLoaded = true;
                })
                .catch (function (message) {
                    vm.Name = "Error";
                    vm.ValidDataLoaded = true;
                });

            }

Update 1:

I changed the filter function after debugging because it was wrongly implemented when I first explained, I even used some console.log and I see sometimes it prints true and sometimes it prints false to the console. However, I put a breakpint inside the IF and its never executing the push, and the array is always empty.

https://www.screencast.com/t/hRTEgvboCmX

My updated piece of code:

// creates filtered list item values var createFilteredListItemsWithValues = createListItemValues( function(listItemValues) {

            var x1=listItemValues && typeof listItemValues.FileRef === "string" && listItemValues.FileRef.split("/")[4];
            var x2= currentBillCyclePath.split("/")[8]
            console.log(x1===x2);


            return !(//pass filter function to createListItemValues
              listItemValues && 
              typeof listItemValues.FileRef === "string" &&
              listItemValues.FileRef.split("/")[4]
            ) === currentBillCyclePath.split("/")[8];
          }
        );
Luis Valencia
  • 32,619
  • 93
  • 286
  • 506
  • 3
    Wow, this code **really** wants breaking up into smaller pieces you can then combine. – T.J. Crowder May 25 '18 at 09:56
  • inherited code by previous guy that works on production, so I just need to filter out some of the results. You should see the entire .js, like 2000 lines – Luis Valencia May 25 '18 at 09:57
  • 1
    It's not the length that counts. – Dave Newton May 25 '18 at 10:00
  • Is this for node? If you refactor this part then it's possible to take out $q and use native promises – HMR May 25 '18 at 10:07
  • *"inside the while, that value is not present anymore its undefined"* **What** value? – T.J. Crowder May 25 '18 at 10:07
  • Looking at the code a bit it seems you are asynchronously mutating `listItemsWithValues` instead of resolving promises with useful values. This can get very confusing. Maybe have `addContentType` resolve to a listItemValue. – HMR May 25 '18 at 10:23
  • Avoid the [deferred antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it)! – Bergi May 25 '18 at 10:27
  • So you're saying that in the `while (enumerator)` loop that fills the `listItemsWithValues` the values are not present, then `addContentType` adds them in, and in the promise callback they are present? – Bergi May 25 '18 at 10:29
  • inside the while/foreach, the value of the parameter currentBillCyclePath is undefined, but outside the while before .getlistitems, the value is present. – Luis Valencia May 25 '18 at 10:46

1 Answers1

1

I have tried to clean up the code a little, for example; removed the catch and reject with no information. Maybe you can give it a try and see if you get rejections.

Since a lot of the processing of GetRelatedBillingDocumentsFromList is done in separate functions you can debug these functions and see if they are doing what you intended.

var createQuery = function(viewFields,clientCode) {
  return '<View Scope="RecursiveAll">' +   viewFields + 
            '<Query>' +
                '<Where>' +
                    '<And>' +
                        '<Eq>' +
                            '<FieldRef Name="ClientCode" />' +
                            '<Value Type="Text">'+ clientCode + '</Value>' +
                        '</Eq>' +
                        '<Neq>' +
                            '<FieldRef Name="ContentType" />' +
                            '<Value Type="Computed">Bill Cycle</Value>' +
                        '</Neq>' +
                    '</And>' +
                '</Where>' +
            '</Query>' +
        '</View>';
};
var createListItemValues = function(filter) {
  return function(listItems,selectProperties) {
    var listItemsWithValues = [];
    if (listItems) {
      var enumerator = listItems.getEnumerator();
      while (enumerator.moveNext()) {
        var listItem = enumerator.get_current();
        var listItemValues = [];

        selectProperties
          .forEach(function (propertyName) {
            var value = listItem.get_item(propertyName);
            if (propertyName === "JobCodesMulti") {
              jobvalue = "";
              value.forEach(function (jobvalues) {
                jobvalue += jobvalues.get_lookupValue() + ";";
              })
              listItemValues[propertyName] = jobvalue;
            } else {
              listItemValues[propertyName] = value;
            }
          });
        if(filter(listItemValues)){//only push if filter returns true
          listItemsWithValues.push(listItemValues);
        }
      }
    }
    return listItemsWithValues;
  };
};
var processListItemWithValue = function(listItemsWithValues) {
  return function(listItem) {
    var fileDirRef = listItem["FileRef"];
    var id = listItem["ID"];
    var title = listItem["Title"];
    var serverUrl = _spPageContextInfo.webAbsoluteUrl.replace(_spPageContextInfo.webServerRelativeUrl, "");
    var dispFormUrl = serverUrl + "/sites/billing/_layouts/15/DocSetHome.aspx?id=" + fileDirRef;
    var parentLink = listItem["FileRef"];
    //!!!PLEASE NOTE: made arrayofstrings a local variable
    var arrayofstrings = parentLink.split("/");
    var billCycleFolderName = arrayofstrings[arrayofstrings.length - 2];
    arrayofstrings.pop();
    var hyperLink = '<a href="' + arrayofstrings.join('/') + '">' + billCycleFolderName + '</a>';
    listItem["Bill Cycle"] = hyperLink;
    listItemsWithValues["Document Type"] = getContentTypeOfCurrentItem(listItem.ID.toString());
  }
};

function GetRelatedBillingDocumentsFromList(selectProperties, currentBillCyclePath, clientCode, jobCodes, engagementCode, enhanceFunctions) {
  $log.info("Retrieving related billing documents for bill cycle with name [" + currentBillCyclePath + "]");
  //pass filter function to createListItemValues to get a new function that
  //  creates filtered list item values 
  var createFilteredListItemsWithValues = createListItemValues(
    function(listItemValues) {
      return !(//pass filter function to createListItemValues
        listItemValues && 
        typeof listItemValues.FileRef === "string" &&
        listItemValues.FileRef.split("/")[4]
      ) === currentBillCyclePath;
    }
  );
  var webUrl = _spPageContextInfo.webAbsoluteUrl;
  selectProperties = selectProperties.concat("ContentTypeId");
  var viewFields = spService.ConvertSelectPropertiesToViewFields(selectProperties);
  // query must return the documents for the same client but in other bill cycles not the current one
  var camlQuery = createQuery(viewFields,clientCode);
  var billCyclesListId = "{c23bbae4-34f7-494c-8f67-acece3ba60da}";
  //return a promise like here so the caller knows if something went wrong
  return spService.GetListItems(billCyclesListId, camlQuery, selectProperties)
  .then(
    function(listItems){
      console.log("currentBillCyclePath:",currentBillCyclePath);
      var listItemsValues = createFilteredListItemsWithValues
        (listItems,selectProperties);
      return $q.all(listItemsValues.map(addContentType))
      .then(function(){ return listItemsValues; })//finished asynchronously mutating array of listItems
    }
  ).then(
    function(listItemsWithValues) {
      listItemsWithValues.forEach(processListItemWithValue(listItemsWithValues));
      return $q.all(
        spService.SpSearchQuery.EnhanceSearchResults(listItemsWithValues, enhanceFunctions)
      )
    }
  )
}
HMR
  • 37,593
  • 24
  • 91
  • 160
  • thanks for this, but I dont see the answer to my question here, I need to filter out some results based on a condition like this: !currentBillCyclePath.contains(listItemValues.FileRef.split("/")[4]) – Luis Valencia May 25 '18 at 10:49
  • before pushing to the array: listItemsWithValues.push(listItemValues); – Luis Valencia May 25 '18 at 11:01
  • @LuisValencia Updated the answer and added a filter to `createListItemValues ` – HMR May 25 '18 at 11:15
  • trying to understand this syntax. const listItemsValues = createListItemValues ( listItemValues=>!(//filter function listItemValues && typeof listItemValues.FileRef === "string" && listItemValues.FileRef.split("/")[4]) === currentBillCyclePath ) (listItems,selectProperties); – Luis Valencia May 25 '18 at 11:25
  • please see my update with a small syntax error I cant figure oout – Luis Valencia May 25 '18 at 11:34
  • @LuisValencia `createListItemValues` is a function returning a function, I updated the answer to pass the filer function first. When you pass a filter function to `createListItemValues` it returns a function that takes listItems and selectProperties and returns list items with values (where some items are filtered out based on the filter function) – HMR May 25 '18 at 11:38
  • @LuisValencia Your error is probably in an older browser (IE11?) I assume you were using nodejs but you can re write arrow syntax functions to classic ECMAScript or use something like webpack to support older browsers. `param=>returnValue` is `function(param){return returnValue}` and `param1=>param2=>value` is `function(param1){return function(param2){return value}}` – HMR May 25 '18 at 11:41
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/171776/discussion-between-hmr-and-luis-valencia). – HMR May 25 '18 at 11:45
  • I still have the same syntax error on the exact same location, on my 2nd update above I also pasted the code that calls the GetRelatedBillingDocumentsFromList method, the method name is GetData. I thought the syntax error was due to the double quotes so I tried to escape double quoutes with \ but still nothing – Luis Valencia May 25 '18 at 14:04
  • @LuisValencia what syntax error are you getting? The image shows arrow function but the new code in my answer does not use that code. – HMR May 25 '18 at 14:08
  • line 110, char 4 which is empty lol. https://www.screencast.com/t/ysIopHzay – Luis Valencia May 25 '18 at 14:21
  • @LuisValencia I changed all const to var see if that works (IE 11 should recognize const though). You can also try to add `;` like so `;var createQuery = function(viewFields,clientCode) {` And try with Chrome to see if you still get errors when the code runs. – HMR May 25 '18 at 15:32