Обратното извикване на Fadein не работи правилно с json данни, заредени с ajax

Това е страница с дизайнерско портфолио. При зареждане JSON данните се извличат чрез ajax и един от ключовете се използва за генериране на списък с „.project-links“ (нито един проект не се показва при зареждане и изображенията на проекта се зареждат само когато е избран проект ( вижте функцията showProj)). Въпросът ми се отнася до затихването/затихването: изображенията все още рисуват върху екрана след завършване на затихването, въпреки че съдържанието на проекта е дефинирано/заредено в рамките на обратното извикване на fadeOut; може ли някой да ме просветли как мога да настроя това, така че fadeIn да не работи, докато не се заредят projImages?

Благодаря ти, свс.

function ajaxReq() {
    var request = new XMLHttpRequest();
    return request;
}


function makeLinks(projects) { // result = getJsonData > request.responseText
    var projectList = document.getElementById("project-list");

    for (var project in projects) {
        if (projects[project].status !== "DNU") {
            var projectId = projects[project].id;
            var listItem = "<li><a class=\"project-link\" id=\""+projects[project].project+"\" href=\"#\">" + projects[project].project + "</a></li>";
            projectList.innerHTML += listItem;
        } // if !DNU
    }

    // ADD EVENT LISTENERS
    var projLink = document.getElementsByClassName("project-link");
    for (var i = 0; i < projLink.length; i++) {
        var projId = projLink[i].id;
        //projLink[i].dataset.projIx = [i];
        projLink[i].addEventListener("click", showProject, false);
    }


    var showNext = document.getElementById("show-next");
    var showPrev = document.getElementById("show-previous");
    showNext.addEventListener("click", showProject, false);
    showPrev.addEventListener("click", showProject, false);

    // ARROW KEYS [not invoking the showProject function]
    $(document).keydown(function(e) {
        if(e.which==37) { // LEFT arrow
            $(showPrev).click(showProject);
            console.log("previous");
        } else
        if(e.which==39) { // RIGHT arrow
            $(showNext).click(showProject);
            console.log("next");
        }
    })


    function showProject(projId) {

        var intro = document.getElementById("intro");
        if (intro) {
            intro.parentNode.removeChild(intro);
        }
        projId.preventDefault();

        var projLinks = document.getElementsByClassName("project-link"); // array

        var selIx = $(".selected").index();


        // ###### CLICK PREVIOUS/NEXT ######
        if (this.id === "show-previous" || this.id === "show-next") {

            // 1a. if nothing is .selected
            if (selIx < 0) {
                if (this.id === "show-previous") {
                    var selIx = projLinks.length-1;
                }
                else if (this.id === "show-next") {
                    var selIx = 0;
                }
            }

            // 1b. if .selected:
            else if (selIx > -1) {
                if (this.id === "show-previous") {
                    if (selIx === 0) { // if @ first slide
                        selIx = projLinks.length-1;
                    }
                    else {
                        selIx --;
                    }
                }
                else if (this.id === "show-next") {
                    if (selIx === projLinks.length-1) { // if @ last slide
                        selIx = 0;
                    }
                    else {
                        selIx ++;
                    }
                }
            }
            var selProjLi = projLinks[selIx]; // => li
        } // click previous/next


        // ###### CLICK .project-link ######
        else if (this.id !== "show-previous" && this.id !== "show-next") {
            var selIx = $(this).closest("li").index();
        }


        // FADE OUT, CALLBACK: LOAD NEW PROJECT
        $("#project-display").fadeTo(450, 0.0, function() {

            // ###### ALL ######
            $(".selected").removeClass("selected");


            var projId = projLink[selIx].id;
            var selProjLi = projLink[selIx].parentElement;
            selProjLi.className = "selected";

            var projectDisplay = document.getElementById("project-display");

            // set vars for the project display elements:
            var projName = document.getElementById("project-name"); // h3
            var projTools = document.getElementById("project-tools");
            var projNotes = document.getElementById("project-notes");
            var projImages = document.getElementById("project-images");

            // disappear the metadata elements 'cause sometimes they'll be empty
            projTools.style.display = "none";
            projNotes.style.display = "none";
            testimonial.style.display = "none";

            for (var project in projects) { // 'Projects array' -> project
                if (projects[project].project === projId) {

                    var activeProj = projects[project];

                    projName.innerHTML = activeProj.project;

                    // maintain centered display of project-metadata: check for a value, else the element remains hidden
                    if(activeProj["tools used"]) {
                        projTools.style.display = "inline-block";
                        projTools.innerHTML = activeProj["tools used"];
                    }
                    if(activeProj.notes) {
                        projNotes.style.display = "inline-block";
                        projNotes.innerHTML = activeProj.notes;
                    }
                    if(activeProj.testimonial) {
                        testimonial.style.display = "inline-block";
                        testimonial.innerHTML = activeProj.testimonial;
                    }

                    // HOW TO ENSURE THESE ARE ALREADY LOADED ***BEFORE #project-display FADES IN***
                    projImages.innerHTML = "";
                    for (var i = 0; i < activeProj.images.length; i++ ) {
                        projImages.innerHTML += "<img src=\"" + activeProj.images[i].url + "\" />";
                    }
                } // if project id ...
            } // for (var obj in data)
        }) // fade out

        $("#project-display").fadeTo(600, 1.0);

    } // showProject
} // makeLinks

function getJsonData() {
    var request = ajaxReq();
    request.open("GET", "/json/projects.json", true);
    request.setRequestHeader("content-type", "application/json");
    request.send(null);
    request.onreadystatechange = function() {
        if (request.readyState === 4) {
            if (request.status === 200) {
                //makeLinks(request.responseText);
                var projects = JSON.parse(request.responseText);
                var projects = projects["Projects"];
                makeLinks(projects); // makeLinks = callback
                return projects;
            }
        }
    } // onreadystatechange
} // getJsonData

getJsonData(makeLinks);

person user1613163    schedule 24.10.2014    source източник


Отговори (1)


Можете да добавите събитие за зареждане към изображенията и да стартирате fadeOut, когато всички изображения са заредени.

Тъй като ще ви трябват множество изображения, за да завършите зареждането, избрах да следя кои зареждания са завършени, като използвам масив от jQuery.Deferred() обекти. След като всички отложени са решени, можете да стартирате избледняващата анимация.

Ето една функция, която трябва да работи:

function fadeWhenReady(projImages, images) {
    projImages.innerHTML = "";
    var loads = []; //create holding bin for deferred calls

    //create images and attach load events
    for (var i = 0; i < activeProj.images.length; i++ ) {
        var deferred = $.Deferred();
        var img = $("<img src=\"" + activeProj.images[i].url + "\" />");
        img.on("load", function() { deferred.resolve() }); //after image load, resolve deferred
        loads.push(deferred.promise()); //add the deferred event to the array
        img.appendTo(projImages); //append image to the page
    }

    //when all deferreds are resolved, then apply the fade
    $.when.apply($, loads).done(function() {
        $("#project-display").fadeTo(600, 1.0); 
    });
}

Във вашия function showProject премахнете обаждането си до $("#project-display").fadeTo(600, 1.0); и заменете редовете по-долу с извикване на функцията fadeWhenReady.

projImages.innerHTML = "";
for (var i = 0; i < activeProj.images.length; i++ ) {
    projImages.innerHTML += "<img src=\"" + activeProj.images[i].url + "\" />";
}

P.S. Използвате странна комбинация от jQuery и ванилен javascript. Обажданията до document.getElementById() не ми пречат толкова много, но със сигурност бих препоръчал да замените вашите XMLHttpRequests с jQuery. ajax().

person Dave    schedule 24.10.2014
comment
Благодаря, Дейв, много го оценявам. Щях да отговоря много по-рано, но аз съм не толкова щастливият собственик на MacBook Pro от 2011 г., така че губя много часове при рестартиране. - person user1613163; 26.10.2014
comment
Що се отнася до вашата помощ: първо, благодаря за предизвестието относно: .Deferred; Мисля, че разбирам същността на това, но изпитвам объркване в обхвата; къде точно трябва да живее функцията fadeWhenReady? А относно моята комбинация от js & jq: изучавам js (знам малко jQ), опитвайки се да сведа до минимум използването на jQ. Но в интерес на целесъобразността и простотата използвам jQ за манипулации и избледняване на класове, които, между другото, бяха последваща мисъл и изглеждаха подходящо използване на jQ. По същество моето невежество е как да избледнявам елементи, които се зареждат чрез ajax/json. Благодаря отново за допълнителната помощ. - person user1613163; 26.10.2014
comment
За мен не е очевидно защо имате проблеми с обхвата. Бих се опитал да поставя новата функция на същото ниво като вашите ajaxReq, makeLinks и getJsonData функции. - person Dave; 28.10.2014
comment
Благодаря, Дейв. За мен също не е очевидно ;) Ако извикам fadeWhenReady(projImages, images); тогава 'изображенията не са дефинирани'; ако пропусна аргументите за изображения (или и двете), тогава activeProj не е дефиниран ... освен ако не го замърся с повтарящи се декларации на която и да е променлива, следователно моето продължаващо объркване в обхвата. - person user1613163; 28.10.2014
comment
Мисля, че трябва да е fadeWhenReady(projImages, activeProj.images); - person Dave; 28.10.2014