Задать вопрос
Ответы пользователя по тегу JavaScript
  • Как отменить событие после его выполнения?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега JavaScript
    $(e).one('click', function () {
      в следующий раз не вызывать эту функцию при клике на $(e)
    })

    Документация
    Ответ написан
    Комментировать
  • Owlcarousel 1.3. Как получить индекс активного слайда?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега JavaScript
    Ведь прямо на той странице написано:
    updateResult(".currentItem", this.owl.currentItem);
    Ответ написан
  • Как навесить обработчик на коллекцию элементов?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега JavaScript
    Проблема в том, что вы пытаетесь навесить обработчик на коллекцию элементов, которая возвращается функцией querySelectorAll. Такой возможности нет, нужно обходить эту коллекцию и навешивать обработчик на каждый элемент отдельно:
    var buttonItems = document.querySelectorAll('.button-item'),
        index, button;
    
    for (index = 0; index < buttonItems.length; index++) {
        button = buttonItems[index];
        button.addEventListener('click', function (event) {
            console.log('click');
            event.preventDefault();
        });
    }

    Пример

    Обратите внимание, что такой способ установки обработчика в цикле не очень хорош - при каждой итерации создается новая функция-обработчик, что засоряет память и этот обработчик невозможно потом удалить, поскольку создаваемая функция безымянна и ссылка на нее нигде не сохраняется.
    Ну в принципе такой код не очень опрятный.

    Лучше делать так:
    var buttons = document.querySelectorAll('.button-item'),
        index, button;
    
    for (index = 0; index < buttons.length; index++) {
        button = buttons[index];
        button.addEventListener('click', clickHandler);
        button.addEventListener('dblclick', doubleClickHandler);
    }
    
    function clickHandler(event) {
        console.log('click', this.innerText);
        event.preventDefault();
    }
    
    function doubleClickHandler(event) {
        console.log('doubleclick', this.innerText);
        this.removeEventListener('click', clickHandler);    
        this.removeEventListener('dblclick', doubleClickHandler);
    }
    Ответ написан
  • Как сделать так, чтобы функция выполнялась только после того, как другая завершится?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега JavaScript
    Дисклеймер
    Кому не нравится название "обещания", мысленно заменяйте его на то, которое считаете подходящим. Я выбрал именно его, чтобы концепция, лежащая в их основе, была интуитивно понятна.

    Если функция асинхронная, то лучше всего использовать обещания, что вы и попытались сделать (интерактивный пример).
    one().done(two);
    
    function one() {
        var dfd = new $.Deferred();
    
        // Запускаем асинхронную задачу. Например, ajax-запрос.
        setTimeout(function () {
            var foo = 'bar';
    
            // "Выполняем обещание", передавая в него какую-то информацию.
            // Передавать аргументы, разумеется, не обязательно.
            dfd.resolve(foo);
        }, 2000);
    
        // Возвращаем из функции обещание, на которое могут подписаться другие функции.
        // Обратите внимание, этот код выполнится до того, как завершится асинхронная задача.
        return dfd.promise();
    }
    
    function two(foo) {
        // Обрабатываем данные, полученные внутри асинхронной функции one.
        console.log('two', foo);
    }

    Для трех функций расклад немного сложнее, но принцип такой же.
    Есть и более элегантный способ запуска цепочки из трех функций:
    код
    one().then(two, onOneError).then(three, onTwoError);
    
    function one() {
        var dfd = new $.Deferred();
    
        setTimeout(function () {
            console.log('one');
            
            if (Math.round(Math.random() * 10) >= 5)
            {
                dfd.resolve();
            }
            else
            {
                dfd.reject();
            }
        }, 1000);
    
        return dfd.promise();
    }
    
    function two() {
        var dfd = new $.Deferred();
    
        setTimeout(function () {
            console.log('two');
            
            if (Math.round(Math.random() * 10) >= 5)
            {
                dfd.resolve();
            }
            else
            {
                dfd.reject();
            }
        }, 1000);
    
        return dfd.promise();
    }
    
    function three() {
        setTimeout(function () {
            console.log('three');
        }, 1000);
    }
    
    function onTwoError() {
        console.log('twoError', arguments);
    }
    
    function onOneError() {
        console.log('oneError', arguments);
    }

    Обратите внимание, что в этом примере показано, что обещания можно не только выполнять, но и отказываться от них и такие ситуации нужно обрабатывать отдельно.


    Обещания - самый современный и удобный вариант, с ними код становится чище и понятнее. Единственная проблема, связанная с ними - это необходимость использовать сторонние библиотеки или полифилы, потому что обещания пока поддерживаются далеко не во всех браузерах.

    Другой вариант - передавать callback, но это прямой путь в callback hell. Для запуска трех и более функций подряд я его не рекомендую - смотрите сами, на что становится похож код:
    one(function () {
        two(three)
    });
    
    function one(callback) {
        console.log('one');
        setTimeout(callback, 1000);
    }
    
    function two(callback) {
        console.log('two');
        setTimeout(callback, 1000);
    }
    
    function three() {
        console.log('three');
    }


    Есть еще один (очень, очень, очень плохой) вариант, основанный на таймерах и внешних флагах. Никогда так не делайте (код для системы из трех функций еще хуже).

    Если внутри функций ничего асинхронного нет, то можно просто вызвать их друг за другом - следующая и так запустится после предыдущей (пример).
    Ответ написан
    5 комментариев
  • JS API и REST API - это разные понятия?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега JavaScript
    Вы путаете теплое с мягким.
    REST - это методология, работа с таким апи может быть реализована на любых технологиях (включая js), реализация на стороне сервера - тоже.
    JS API - это уже конкретная реализация клиентской библиотеки. На сервере, с которым работает эта библиотека, при этом может быть REST апи.
    Ответ написан
    2 комментария
  • Как правильно отлаживать JS?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега JavaScript
    Как узнать, в каком месте вылезла ошибка?
    console.error выводит полный стек вызовов со ссылками на конкретные строки конкретных скриптов.
    Еще очень удобно включить режим "Pause on exceptions", в нем при выпадении ошибки автоматически включается дебагер. Но для этого Developer Tools должны быть открыты (хотя, если вы веб-разработчик, то они в принципе никогда не закрываются).
    Ну а все остальные проблемы легко решаются при помощи дебагера. Там и значения переменных и стек вызовов и логику можно пошагово посмотреть.
    Ответ написан
    2 комментария
  • Почему такой вариант работы с DOM считается темной стороной силы?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега JavaScript
    Потому что операции работы с DOM затратны по ресурсам и времени. Если элемент в DOM еще не добавлен, изменять его гораздо дешевле.

    Но в вашем конкретном случае это нормально - вы же работаете со всеми ячейками строки, а не с одной создаваемой. Разве что добавление кнопки "Добавить в корзину" лучше сделать сразу в создаваемую ячейку, тогда и искать ее не надо будет и на операциях с DOM сэкономите.

    Я бы переписал так:
    var classes = ['item-id', 'item-title', 'item-price'],
        table = document.getElementById('table'),
        rows = table.getElementsByTagName('tr'),
        rowIndex, cellIndex, cells, currentRow, currentCell, addToCartCell;
    
    // Пропускаем первую строку, потому что в ней находится заголовок таблицы
    for (rowIndex = 1; rowIndex < rows.length; rowIndex++) {
        currentRow = rows[rowIndex];
        cells = currentRow.getElementsByTagName('td');
    
        for (cellIndex = 0; cellIndex < cells.length; cellIndex++) {
            currentCell = cells[cellIndex];
            currentCell.setAttribute('class', classes[cellIndex]);
        };
    
        addToCartCell = document.createElement("td");
        addToCartCell.innerHTML = '<a class="add_item">Добавить в корзину</a>';
        currentRow.appendChild(addToCartCell);
    };

    Обратите внимание, что упростив код и дав понятные названия переменным, мы избавились от необходимости его комментировать.
    Многие разработчики (и я в их числе) считают необходимость в комментариях признаком плохого кода. Комментировать можно и нужно зачем мы что-то делаем, но что код делает, должно быть понятно из него самого.
    Я оставил один полезный комментарий в качестве примера.

    Помимо этого, мы перенесли объявления переменных в самое начало условной функции, поскольку это широкораспространенное соглашение, облегчающее понимание кода.

    Можно было бы пойти чуть дальше и разбить код на маленькие независимые функции:
    function getTable() {
        return document.getElementById('table')
    }
    
    function getRows(table) {
        var allTableRows = table.getElementsByTagName('tr'),
            rows = [],
            index;
    
        // Пропускаем первую строку, потому что в ней находится заголовок таблицы
        for (index = 1; index < allTableRows.length; index++) {
            rows.push(allTableRows[index]);
        }
    
        return rows;
    }
    
    function appendAddToCartButton(row) {
        var cell = document.createElement("td");
        cell.innerHTML = '<a class="add_item">Добавить в корзину</a>';
        row.appendChild(cell);
    }
    
    function setCellsClasses(row) {
        var classes = ['item-id', 'item-title', 'item-price'],
            cells = row.getElementsByTagName('td'),
            index;
    
        // Обратите внимание, что здесь мы итерируем по классам, а не по ячейкам
        // В том случае, если в функции prepareTable кто-то по ошибке
        // поменяет местами строки добавления классов и кнопки добавления в корзину
        // код не сломается
        for (index = 0; index < classes.length; index++) {
            cells[index].setAttribute('class', classes[index]);
        }
    }
    
    function prepareTable() {
        var table = getTable(),
            rows = getRows(table),
            rowIndex, currentRow;
    
        for (rowIndex = 0; rowIndex < rows.length; rowIndex++) {
            currentRow = rows[rowIndex];
            setCellsClasses(currentRow);
            appendAddToCartButton(currentRow);
        }
    }
    
    prepareTable();

    Но в данном случае, скорее всего, это уже излишне.
    Ответ написан
    Комментировать
  • Как изменить данные с помощью цикла в jquery?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега JavaScript
    Вам нужно сделать замыкание, чтобы работать с копией переменной, а не с ней самой, поскольку код внутри цикла выполняется после его завершения, когда переменная i имеет максимальное значение.
    https://learn.javascript.ru/closures-usage#армия-ф...
    Ответ написан
    Комментировать
  • Как сделать что бы баннер открывались в новой вкладке?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега JavaScript
    var glob_tag = "<a href='" + glob_lnk + "' target='_blank'>";
    Ответ написан
    Комментировать
  • Как в Javascript определить что в инпут был введен именно вопрос?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега JavaScript
    Вы не указали, что именно у вас не работает.
    Разве что, проверка регистрозависимая. Отвязать от регистра можно так.
    Ответ написан
    Комментировать
  • Как ограничить кол-во dots в slick слайдере?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега CSS
    Количество точек = общее количество слайдов / количество показываемых за раз слайдов
    А за зацикливание отвечает опция infinite.
    Ответ написан
    4 комментария
  • Как найти элемент, имеющий определенный атрибут?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега JavaScript
    $('[data-create-type]')
    Пример
    Документация
    Ответ написан
    Комментировать
  • Как найти value с определенными символами?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега JavaScript
    У вас value - это число. Разумеется, у него нет метода match.
    Вот так ошибки не будет:
    var value = '' + 12;

    Ну а так работает без дополнительных манипуляций:
    var value = '&#x431';
    if(value.match(/&#/g)) { console.log(value); }
    Ответ написан
    7 комментариев
  • Что может делать этот внедренный на сайт javascript код?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега JavaScript
    Судя по коду (обработка сообщений, доктайпы, обфускация), это код какого-то расширения для браузера.
    Походите по другим сайтам (этот код должен быть на каждом) или зайдите из другого браузера (этого кода не должно быть), чтобы убедиться.
    Ответ написан
    Комментировать
  • Как грамотно загрузить HTML страницу в другую HTML страницу на JavaScript?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега JavaScript
    Если грамотно, то вот так:
    var request = $.get('common.htm');
    
    request.done(function(response) {
        var $response = $(response);
    
        // Вместо $response.find(), возможно, придется использовать $response.filter()
        // Это зависит от структуры возвращаемого документа
        $('#header').html($response.find('.header').html());
        $('#menu').html($response.find('.menu').html());
        $('#footer').html($response.find('.footer').html());
    });
    Ответ написан
    Комментировать
  • Как выполнить код после завершения setInterval?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега JavaScript
    Прекрасный способ писать асинхронный код синхронно - промисы. Пример.
    Вместо jq, разумеется, можно использовать любую другую реализацию.
    Ответ написан
    1 комментарий
  • Почему не отправляется post запрос в laravel 5 на другую страницу?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега JavaScript
    500 статус означает, что на сервере произошла ошибка.
    Откройте лог и посмотрите в чем проблема.
    Если сами не разберетесь, не забудьте в вопрос добавить свой код и релевантные записи из лога.
    Ответ написан
  • Как правильно сгенерировать HTML с текстом из json?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега JavaScript
    Я бы реализовал что-то вроде этого.
    $.fn.setLanguage = function (options) {
        options = $.extend({
            language: 'ru',
            text: this.attr('data-text')
        }, options);
    
        var make = function () {
            var el = $(this);
            $.ajax({
                url: options.language + '.json',
                dataType: 'json',
                success: function (data) {
                    var html = data[options.text];
    
                    if ($.isFunction(options.callback)) {
                        options.callback(html);
                    } else {
                        el.html(html);
                    }
                }
            });
        };
    
        return this.each(make);
    };
    
    var wrapper = $('<div><i>Blah</i> <span>replaced</span> <b>Blah</b></div>');
    
    wrapper.setLanguage({
        text: 'login_error',
        callback: $.proxy(function (html) {
            $(this).find('span').html(html);
        }, wrapper),
    });
    
    $('body').append(wrapper);

    А еще лучше, конечно, сделать свое событие и слушать его.

    Ну а вообще можно и не делать ajax-запрос делать. Проще получить объект переводов при старте страницы один раз и работать дальше с ним. Тогда и проблемы асинхронности не станет.
    Ответ написан
  • Как получить Имя и Аватар пользователя Facebook?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега JavaScript
    Начните отсюда.
    Ответ написан
    Комментировать