0

New to SharePoint development and not understanding how things work:

I have a "directory search" custom webpart on my home page. It currently only works on the second search. I guess the AJAX call doesn't run until the first search to grab data which is why the search works only after the 2nd try.

How do I run the data on page load so that I can access the data right away from the first directory search?

I've tried placing the JS file onto the page, but it isn't reading the elements in the webpart...

AJAX Call

var employees = [];    
function getADInfo(){
  $.ajax({
    url: "http://mes-server/CustomWebparts/DirectorySearch/roster.txt",
    method: 'GET',
    // dataType: 'json',
    cache: false,
    success: function(data) {
        console.log('success from getADInfo in JS');
        // console.log(JSON.parse(data));
        var jsonData = JSON.parse(data);
        // employees.push(...jsonData);
        Array.prototype.push.apply(employees, jsonData);
        console.log(employees);
    },
    error: function(err) {
        console.error(err);
    }
  })
}

handleFilters This is giving me an error if I place the JS file on the home page. It runs fine when the JS file is run from the directory search webpart, but the search occurs on 2nd try.

var searchInput = document.querySelector('.search');
function handleFilters(){
  searchInput.addEventListener('keyup', displayMatches);
}

HTML

<head>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
    <link  rel="stylesheet" href="/CustomWebParts/DirectorySearch/directory.css" type="text/css">

</head>
<body>
    <div id="employee-directory">
        <p class="search-by">Search by first or last name</p>
        <searchform class="search-form">
            <div class="search-container">
                <input type="text" id="search-box" class="search" placeholder="Search Name" autocomplete="off">
                <button type="submit" id="search-button"><i class="fa fa-search"></i></button>
            </div>
            <ul class="suggestions"></ul>
        </searchform>
        <div id="directory-results">
            <p class="incorrect-info">Incorrect Information?<br>Please contact IT Support</a>.</p>
        </div>
    </div>

<script src="/CustomWebparts/DirectorySearch/directory.js"></script>
</body>

JS File

console.log('directory.js connected');

var employees = [];
var searchInput = document.querySelector('.search');
var suggestions = document.querySelector('.suggestions');

function getADInfo(){
    $.ajax({
        url: "http://mes-server/CustomWebparts/DirectorySearch/roster.txt",
        method: 'GET',
        // dataType: 'json',
        cache: false,
        success: function(data) {
            console.log('success from getADInfo');
            // console.log(JSON.parse(data));
            var jsonData = JSON.parse(data);
            // employees.push(...jsonData);
            Array.prototype.push.apply(employees, jsonData);
            console.log(employees);
        },
        error: function(err) {
            console.error(err);
        }
    });
}

function findMatches(wordToMatch, employees) {
    return employees.filter(function(person) {
        var regex = new RegExp(wordToMatch, 'gi');
        var nameString = person.Name.split(", ")[1] + " " + person.Name.split(", ")[0];
        var displayFirstName = person.DisplayName.split(", ")[1];
        return person.GivenName.match(regex) || person.Surname.match(regex) || nameString.match(regex) || displayFirstName.match(regex);
    });
}

function displayMatches() {
    $('.suggestions').show();
    var matchArray = findMatches(this.value, employees);
    var html = [];

    for(var i=0; i < matchArray.slice(0,10).length; i++){
        var person = matchArray.slice(0,10)[i];
        var regex = new RegExp(this.value, 'gi');
        var hilight = '<span class="hl">' + this.value + '</span>';
        var firstName = person.GivenName.replace(regex, hilight);
        var lastName = person.Surname.replace(regex, hilight);
        var extension;
        var showdisplayname;


        if (person.DisplayName.split(", ")[1] !== person.GivenName){
            showdisplayname = "(" + person.DisplayName.split(", ")[1] + ")";
            showdisplayname = showdisplayname.replace(regex, hilight);
        } else {
            showdisplayname = "";
        }

        if (person.Phone_Ext1 !== null){
            extension = person.Phone_Ext1;
        } else {
            extension = "N/A"
        }

        var list =
            '<li class="search-item" data-id=' + person.EmployeeID +'>' +
            '<span class="person">' + firstName + ' ' + lastName + ' ' + showdisplayname + '</span>' +
            '<span class="phone-ext">Ext. ' + extension + '</span>' +
            '</li>';

        html.push(list);
    }
    html = html.join('');

    if ($('#search-box').val() == ""){
        suggestions.innerHTML = "";
    } else {
        suggestions.innerHTML = html;
    }
}


function findEmployeeByID(id){
    var result = employees.filter(function(obj) {
        return obj.EmployeeID === id;
    })
    return result
}

function displayEmployeeDetails(employee){
    $('#directory-results').html(detailsTemplate(employee))
}

function detailsTemplate(employee) {
    var nickname = employee.DisplayName.split(", ")[1];
    var showNickname;
    var extension;
    var email;

    if (nickname !== employee.GivenName){
        showNickname = "(" + nickname + ")";
    } else {
        showNickname = "";
    }

    if (employee.Phone_Ext1 === null){
        extension = "N/A";
    } else {
        extension = employee.Phone_Ext1;
    }

    if (employee.mail === null){
        email = "N/A"
    } else {
        email = '<a href="mailto:' + employee.mail + '">' + employee.mail.toLowerCase() + '</a>';
    }

    return (
        '<p class="employee-name"><strong>' + employee.GivenName + ' ' + employee.Surname + ' ' + showNickname + '</strong></p>' +
        '<p class="employee-title">' + employee.Title + '</p>' +
        '<p class="employee-location">' + employee.Office + '</p>' +
        '<p class="employee-ext">Ext: ' + extension + '</p>' +
        '<p class="employee-phone">Phone: ' + employee.PhoneNumber + '</p>' +
        '<p class="employee-email">Email: ' + email + '</p>'
    );
}


/*********************************
           EVENT HANDLERS
 *********************************/
function handleFilters(){
var searchInput = document.querySelector('.search');

    searchInput.addEventListener('keyup', displayMatches);
    // $('#search-box').on('keyup', displayMatches);
}

function handleClick(){
    $('.suggestions').on('click', 'li',function(event){
        event.preventDefault();

        var dataid = $(this).attr('data-id');
        var employee = findEmployeeByID(dataid)[0];
        console.log(employee);

        $('#search-box').val(employee.GivenName + ' ' + employee.Surname);  
        displayEmployeeDetails(employee);

        $('.suggestions').hide();
        $('#search-box').val("");
    })
}

function watchSubmit(){
    $('.search-form').submit(function(event) {
        event.preventDefault();

        if ($('#search-box').val().trim.length === 0){
            $('#directory-results').html(
                '<p class="incorrect-info">Incorrect Information?<br>Please contact IT Support.</p>'
            );
        }

        if ($('.suggestions li').length === 1){
            var dataid = $('.suggestions li').attr('data-id');
            var employee = findEmployeeByID(dataid)[0];
            console.log(employee)
            displayEmployeeDetails(employee);
        }

        $('#search-box').val("");
    })

}

$(watchSubmit);
$(handleFilters);
$(handleClick);
$(getADInfo);
  • Do you have any code snippets so we can understand what order of execution is? – BigRaj Jun 25 at 15:02
  • @BigRaj I've added some code – staysee Jun 25 at 15:24
  • Thank you! How are you calling the functions when the page loads? Typically _spBodyOnLoadFunctionNames.push(<function name>); will ensure that it is run after all of the dom elements are loaded. What function is called on the input that has the class search? – BigRaj Jun 25 at 15:29
  • @BigRaj I'm not familiar with SharePoint so I don't know how to properly call my code to have this work correctly and from where I should be doing these things. So right now all of my code is in a "CustomWebPart" document library and the webpart is connected to the files in that document library. I've tried to place the getADInfo function on page load, and it grabs the data, but it cannot read the html file that is in the webpart. So the searchbox with class .search is not found – staysee Jun 25 at 15:36
  • Just a couple more questions. you said that it only works on the second time. On page load, the ajax call will take a little time, fractions of a second to run, but that's an eternity when it comes to DOM loading. And in order to add the displaymatches keyup event to the search Input handleFilters has to be run at least once. where is handleFilters being called? I think that may be where the issue is. – BigRaj Jun 25 at 15:39
0

I think this is what you're looking for based on the comments above:

var employees = [];    
function getADInfo(){
  $.ajax({
    url: "http://mes-server/CustomWebparts/DirectorySearch/roster.txt",
    method: 'GET',
    // dataType: 'json',
    cache: false,
    success: function(data) {
        console.log('success from getADInfo in JS');
        // console.log(JSON.parse(data));
        var jsonData = JSON.parse(data);
        // employees.push(...jsonData);
        Array.prototype.push.apply(employees, jsonData);
        console.log(employees);
        // Attaching event receiver to searchInput only after retrieving data from roster.txt
        var searchInput = document.querySelector('.search');
        searchInput.addEventListener('keyup',displayMatches);
    },
    error: function(err) {
        console.error(err);
    }
  })
}
// This will make the getADInfo function run once the page is loaded, any other calls to this function should be removed.  
_spBodyOnLoadFunctionNames.push(getADInfo);
  • Am I adding this to my JS file that is in the document library? This doesn't work. The JS file doesn't run until the search button is clicked one. I've put the AJAX call on the Home.aspx file, but that doesn't fix that it cannot find the .search (searchbox) – staysee Jun 25 at 15:59
  • is the directory search custom web part an iframe or page viewer web part? That would cause some JS issues when trying to run it directly from home.aspx. In that case, the ajax call would have to come from the web part itself, and based on your description should be in the JS file. – BigRaj Jun 25 at 16:05
  • it's a webpart. I linked the html in the webpart creator which references the JS file. I tried updating the JS file but it still does not work. the calls do not work until the first search – staysee Jun 25 at 16:11
  • You may need to post the full html and js for the custom web part. There's something missing in how everything is executed. – BigRaj Jun 25 at 16:13
  • Updated with the full original html and js – staysee Jun 25 at 16:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.