Задать вопрос
  • Как навесить обработчик на коллекцию элементов?

    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);
    }
    Ответ написан
  • Сайт оффлайн, как сделать Laravel 4?

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

    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 комментариев
  • Как конкатенировать все скрипты bower через grunt в нужном порядке?

    grunt-bower-concat прекрасно с этим справляется, документация там достаточно подробная и понятная. Вдобавок, он очень гибко настраивается.
    Вы хотя бы пробовали его запускать? Опишите свои проблемы конкретно.
    Ответ написан
    4 комментария
  • JS API и REST API - это разные понятия?

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

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега PHP
    У php нет препроцессора, php - это препроцессор html (PHP: Hypertext Preprocessor)
    А автор видео, скорее всего, говорит о том, что php умирает после выполнения, а программы на ruby и python запущены постоянно.
    Ответ написан
    3 комментария
  • Почему происходит обновление страницы при использовании ajax?

    Вы не выполняете event.preventDefault(); при сабмите формы, вот она и перезагружает страницу - это ее стандартное поведение.
    jQuery('#form').submit(function (event) {
        jQuery.ajax({
            type: "POST",
            url: ajaxurl,
            data: {action: "my_action"},
            beforeSend: function () {
                jQuery('#primer').html('<img src="/img/loading.svg">');
            },
            success: function () {
                 jQuery('#primer').html('Данные изменены');
             }
        });
    
        event.preventDefault();
    });
    Ответ написан
  • Как правильно отлаживать JS?

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

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега MySQL
    SELECT * FROM `order_archive` AS `oa` WHERE `order`.`author_id` = `oa`.`user_id`
    Ответ написан
    Комментировать
  • Почему такой вариант работы с 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();

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

    У вас проблема в синтаксисе CREATE TABLE, там не используется ключевое слово VALUES.
    dev.mysql.com/doc/refman/5.6/en/create-table.html
    Ответ написан
    Комментировать
  • Можно применить blur к background-image: url();?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега CSS
    Довольно подробный ответ.
    tl:dr codepen.io/akademy/pen/FlkzB
    Ответ написан
    Комментировать
  • Как изменить данные с помощью цикла в 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'>";
    Ответ написан
    Комментировать
  • Как поправить вёрстку?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега CSS
    .following-item .following-name {
        padding-left: 85px;
        padding-right: 5px;
    }


    У ".following-item .following-name a" убрать ширину.
    Ответ написан
    Комментировать
  • Выборка из бд по id и get запросы?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега PHP
    $products_id = isset($_GET['id']) ? $_GET['id'] : 0;
    $stmt = $db->prepare('SELECT * FROM rm_products WHERE id=$id' );

    Вы сохраняете id в переменную $products_id, а в запрос передаете $id.
    Ну и как правильно указал Виталий Инчин, в одинарных кавычках переменная не интерполируется.
    Ответ написан
    Комментировать
  • Зачем писать одно и тоже CSS свойство для каждого браузера?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега CSS
    последнее (просто transition) свойство - поддерживают все вышеперечисленные браузеры?

    Если бы это было правдой, то действительно, никакого смысла указывать вендорные префиксы бы не было. Но это не так.
    caniuse.com/#feat=css-transitions
    Решать, использовать или нет вендорные префиксы, нужно в зависимости от проекта и минимально поддерживаемых версий браузеров.
    P.S. Сегодня уже был вопрос на эту тему.
    Ответ написан
    Комментировать
  • Как в Javascript определить что в инпут был введен именно вопрос?

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