Search code examples
angularjssharepointsharepoint-2013sharepoint-jsom

SharePoint JSOM KeywordQuery changing ContentType that it's searching for


I'm currently using AngularJS with the SharePoint JSOM to execute some Keyword Queries against a Result Source.

I've got an angular factory that accepts a ResultSourceName and ResultSourceLevel variables

angular.module('app.services.sharepoint').factory('resultSourceDataSvc', ['$log', '$q', '$timeout', function ($log, $q, $timeout) {
    return function (resultSourceName, resultSourceLevel) {         
        return new ResultSourceDataService($log, $q, $timeout, resultSourceName, resultSourceLevel);
    }
}]);

This is injected into my controllers and they use it like this:

var inTheNewsResultDataSource = resultSourceData('TSToday In The News Result Source', 'SPSite');
inTheNewsResultDataSource.ready(function () {
    inTheNewsResultDataSource.getData(null, IN_THE_NEWS_COLUMNS, IN_THE_NEWS_MAP_COLUMNS)
        .then(function (data) {
            $log.debug('Resolving data:', data);
            deferred.resolve(data);
        },
        function (resp) {
            $log.error('Error while attempting to retrieve In The News data:', resp);
            deferred.reject(resp);
        });
});

The actual meat of it all is handled in the ResultSourceDataService that is returned from my factory, here's the code from it:

function ResultSourceDataService($log, $q, $timeout, resultSourceName, resultSourceLevel) {
    var deferred = $q.defer(),
        promise = deferred.promise,
        context = undefined,
        resultSourceQuery = undefined,
        resultSourceExecutor = undefined,
        properties = undefined;

    $log = $log.getInstance('app.services.sharepoint.resultSourceDataSvc(' + resultSourceName + ')');

    function init() {           
        $log.debug('Initializing new Result Source Data Service for:', resultSourceName, 'on', resultSourceLevel);          

        SP.SOD.registerSod('sp.search.js', '/_layouts/15/sp.search.js');

        SP.SOD.loadMultiple(['sp.js', 'sp.search.js'], function () {
            context = SP.ClientContext ? SP.ClientContext.get_current() : undefined;

            // should probably add error checking to make sure context is loaded here

            resultSourceQuery = new Microsoft.SharePoint.Client.Search.Query.KeywordQuery(context);
            resultSourceExecutor = new Microsoft.SharePoint.Client.Search.Query.SearchExecutor(context);

            resultSourceQuery.set_trimDuplicates(false);

            resultSourceQuery.get_properties().set_item('SourceName', resultSourceName);
            resultSourceQuery.get_properties().set_item('SourceLevel', resultSourceLevel);

            $log.debug('Initialized');
            deferred.resolve();
        });
    }
    init();

    //#region Private Functions
    function setSelectProperties(columnsToRetrieve) {
        properties = resultSourceQuery.get_selectProperties();

        for (var i = columnsToRetrieve.length; i-- > 0;) {
            $log.debug('Adding in property to retrieve', columnsToRetrieve[i]);
            properties.add(columnsToRetrieve[i]);
        }
    }
    function getResults(data, columnsToRetrieve, columnsToMap) {
        return data.map(function (obj, i) {
            var result = columnsToRetrieve.length == 0 ? obj : {};
            for (var j = columnsToRetrieve.length; j-- > 0;) {
                result[columnsToMap[j]] = obj[columnsToRetrieve[j]];
            }
            $log.debug('getResult', result);

            return result;
        });
    }
    //#endregion

    //#region Public Functions
    this.getData = function (keyword, columnsToRetrieve, columnsToMap) {
        var deferred = $q.defer(),
            promise = deferred.promise,
            data = undefined,
            results = [];

        keyword = keyword || '*';
        columnsToRetrieve = columnsToRetrieve || [];
        columnsToMap = columnsToMap || columnsToRetrieve;           

        resultSourceQuery.set_queryText(keyword);
        setSelectProperties(columnsToRetrieve);

        $log.info('Attempting to retrieve data from result source with keyword:', keyword, resultSourceQuery);

        data = resultSourceExecutor.executeQuery(resultSourceQuery);

        context.executeQueryAsync(
            function (sender, args) {
                $log.debug('Data retrieved successfully', data.get_value().ResultTables);
                results = getResults(data.get_value().ResultTables[0].ResultRows, columnsToRetrieve, columnsToMap);                    
                $log.info('Resolving data', results);
                deferred.resolve(results);
            },
            function (sender, args) {
                $log.error('Error with resolving data in ResultSourceDataService', args.get_message());
                deferred.reject(args.get_message());
            });

        return promise;
    }
    this.ready = function (fn) {
        promise.then(fn);
    }
    //#endregion        
}

When I load the page that this code is running on, it runs fine. When I refresh the page, it runs fine. However, if I navigate to this page from any other page within my site, it breaks and returns data as if there was no result source specified.

For some reason, the QueryModification (which if I'm correct, essentially tells it what ContentType we're looking for in the query) is changing. When I originally load the page and I look at the data logged to the console ($log.debug('Data retrieved successfully', data.get_value().ResultTables);), I can drill down into that and see the difference in the QueryModification.

When it runs properly (refreshing the page or navigating to it directly from outside the site), I see a value of ContentTypeId:0x0100A9723709C6D74A77B01EA922C770FDD0*, which is correct. However; if I navigate to the page from inside SharePoint, I see a value of * -ContentClass=urn:content-class:SPSPeople So it's returning results that would show up if I wasn't specifying the Result Source Name.

Any thoughts as to what could be causing this when I'm passing the same exact variables to it?


Solution

  • Don't know why this works, but removing the

            resultSourceQuery.get_properties().set_item('SourceName', resultSourceName);
            resultSourceQuery.get_properties().set_item('SourceLevel', resultSourceLevel);
    

    from the init method and adding it to the getData method fixed the issue. Not sure why it would work since that should always be set before the getData method if the calling code is using the readymethod.

    If anyone sees why this fixed it, please do point it out. In the meantime, my issue is resolved.