Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Как асинхронно вызвать метод? (https://javascript.ru/forum/misc/64037-kak-asinkhronno-vyzvat-metod.html)

PMaster 16.07.2016 14:16

Как асинхронно вызвать метод?
 
Пишу плагин для jQuery. В настройках плагина есть объект, содержащий метод render:

columns: {
            id: {
                name: '',
                isSearch: false,
                isSortable: true,
                render: function (content) {
                    return '<td>' + content[id] + '</td>';
                }
            },


В метод render передаю объект content. Код выполняется асинхронно.
Получаю ошибку:

ReferenceError: id is not defined


Код, из которого вызывается метод:

var request = ajax.index(settings);
request.done(function(result) {
            for (var column in result) {
                html += settings.columns[column].render(content);
            }
        }


Сам объект content:

Object { id=1, type="main", parameter="sitename", ...}


Мне нужно получить доступ к свойствам объекта content в методе render. Подскажите, пожалуйста, как правильно это сделать?

PMaster 16.07.2016 14:48

Есть такой вариант на костылях:

render: function (content) {
                    if (typeof content !== 'undefined') if (typeof content.id !== 'undefined') {
                        return '<td>' + content.id + '</td>';
                    }
                }


Так работает и всё же хотелось бы более грамотное решение. Что бы не писать if (typeof content !== 'undefined') в каждом такой функции.

destus 16.07.2016 15:14

return '<td>' + content['id'] + '</td>';

PMaster 16.07.2016 15:27

Цитата:

Сообщение от destus (Сообщение 422228)
return '<td>' + content['id'] + '</td>';


Так тоже не работает.


destus 16.07.2016 15:31

PMaster,
потому что здесь
for (var column in result) {
                html += settings.columns[column].render(content);
            }

content нигде не определяется.

PMaster 16.07.2016 19:13

Цитата:

Сообщение от destus (Сообщение 422232)
PMaster,
потому что здесь
for (var column in result) {
                html += settings.columns[column].render(content);
            }

content нигде не определяется.

Определяется. Я просто из контекста вырвал кусок кода. Если там console.log(content) сделать, то все Ok.

Erolast 16.07.2016 19:37

Цитата:

Сообщение от destus (Сообщение 422228)
return '<td>' + content['id'] + '</td>';

Какая разница?

Цитата:

Определяется. Я просто из контекста вырвал кусок кода. Если там console.log(content) сделать, то все Ok.
Значит, объявляется, но не определяется.
В консоли написано undefined - значит, undefined. Браузеру виднее.

destus 16.07.2016 20:04

Цитата:

Какая разница?
let obj = {id: 123},
	s;
	
	try{
		s = 'keeeek' + obj[id];
		alert(s);
	}
	catch(e){
		alert(e);
	}

	try{
		s = 'blablabla' + obj['id'];
		alert(s);
	}
	catch(e){
		alert(e);
	}

Erolast 16.07.2016 20:34

А. Я с этим вариантом сравнивал:
Цитата:

return '<td>' + content.id + '</td>';

PMaster 16.07.2016 22:48

Цитата:

Сообщение от Erolast (Сообщение 422262)
Значит, объявляется, но не определяется.
В консоли написано undefined - значит, undefined. Браузеру виднее.


Могу сказать, почему в браузере - undefined. Выше писал, что код асинхронно работает. При инициализации настроек jQuery плагина метод render почему-то запускается, при этом никаких данных никто ему не отправлял.

Видимо это происходит при объединении настроек:
settings = $.extend(true, {}, defaults, options);


На данный момент я добавил еще один параметр async. При асинхронном вызове явно задаю параметр в true:

render: function (async, content) {
    if (async == true) return '<td>' + content.id + '</td>';
 }


Такой код работает, правда с костылем.

рони 16.07.2016 23:12

Цитата:

Сообщение от PMaster
Видимо это происходит при объединении настроек: settings = $.extend(true, {}, defaults, options);

как может вызватся метод обьекта при копировании свойств обьекта?

Erolast 17.07.2016 04:14

Цитата:

При инициализации настроек jQuery плагина метод render почему-то запускается
С какой бы стати ему запускаться?
Проверяй код, наверно, где-то еще вызов рендера есть.

Цитата:

Определяется. Я просто из контекста вырвал кусок кода.
Где он там определяется?
Давай полный код.

PMaster 17.07.2016 16:21

Цитата:

Сообщение от Erolast (Сообщение 422301)
С какой бы стати ему запускаться?
Проверяй код, наверно, где-то еще вызов рендера есть.


Первый раз плагин jQuery пишу, не знаю как это возможно, но я просто alert(1) туда вставлял без вызова render() и алерт срабатывал.

Цитата:

Сообщение от Erolast (Сообщение 422301)
Давай полный код.


Хорошо. Вот вызов плагина:

$(document).ready(function () {
    $('#settings_grid').jsGrid({
        dataset: {
            ajaxUrl: '/jsgrid/settings'
        },
        controls: {
            headerCreate: 'Добавить в настройки',
            headerEdit: 'Редактировать',
            isAdd: true,
            isEdit: true,
            isDelete: true,
            pagination: 'double'
        },
        table: {
            limit: 5,
            orderBy: 'id',
            order: 'asc'
        },
        columns: {
            id: {
                name: '',
                isSearch: false,
                isSearchStrict: true,
                isSortable: true,
                render: function (content) {
                    return '<td>' + content.id + '</td>';
                }
            },
            type: {
                name: 'Тип',
                isSearch: false,
                isSearchStrict: false,
                isSortable: true,
                render: function (content) {
                    return '<td>' + content.type + '</td>';
                }
            },
            parameter: {
                name: 'Параметр',
                isSearch: false,
                isSearchStrict: false,
                isSortable: true,
                render: function (content) {
                    return '<td>' + content.parameter + '</td>';
                }
            },
            name: {
                name: 'Имя',
                isSearch: false,
                isSearchStrict: false,
                isSortable: true,
                render: function (content) {
                    return '<td>' + content.name + '</td>';
                }
            },
            value: {
                name: 'Значение',
                isSearch: false,
                isSearchStrict: false,
                isSortable: true,
                render: function (content) {
                    return '<td>' + content.name + '</td>';
                }
            }
        }
    });
});


Полный код плагина:

/*
 * JsGrid 0.0.1
 */

(function ($) {
    var settings,
        ajax,
        dom,
        defaults = {
        dataset: {
            ajaxUrl: null,
        },
        controls: {
            headerCreate: null,
            headerEdit: null,
            isAdd: true,
            isEdit: true,
            isDelete: true,
            pagination: 'bottom',
            perPageOptions: [10, 20, 50, 100, 500],
            totalName: 'Всего: ',
        },
        table: {
            page: 1,
            limit: 50,
            orderBy: 'id',
            order: 'asc',
            searchColumn: null,
            searchValue: null,
        }
    }

     ajax = {
        request: function (url, method, method_hidden, data) {
            // Ajax запрос в контроллер
            data['_method'] = method_hidden;
            if (method == 'post') {
                return $.post(url, data);
            }
            else {
                return $.get(url, data);
            }
        },
        index: function (settings) {
            // Метод контроллера index
            return this.request(settings.dataset.ajaxUrl, 'get', 'get', settings);
        },
        create: function (settings) {
            // Метод контроллера create
            return this.request(settings.dataset.ajaxUrl + '/create', 'get', 'get', settings);
        },

        store: function (settings) {
            // Метод контроллера store
            return this.request(settings.dataset.ajaxUrl, 'post', 'post', settings);
        },

        edit: function (settings) {
            // Метод контроллера edit
            return this.request(settings.dataset.ajaxUrl + '/' + settings.id + '/edit', 'get', 'get', settings);
        },

        update: function (settings) {
            // Метод контроллера update
            return this.request(settings.dataset.ajaxUrl + '/' + settings.id, 'post', 'put', settings);
        },

        destroy: function (settings) {
            // Метод контроллера destroy
            return this.request(settings.dataset.ajaxUrl + '/' + settings.id, 'post', 'delete', settings);
        }
    };

    dom = {
        render: function (container, settings) {
            // Отображение данных
            var request = ajax.index(settings);
            request.done(function (result) {
                // Элементы управления
                var html = '<div>' + settings.controls.totalName + result.total + '</div>';

                // Таблица
                html += '<div class="table-responsive"><table class="table">';

                // Заголовки
                html += '<tr>';
                for (var column in settings.columns) {
                    html += '<th>' + settings.columns[column].name + '</th>'
                }
                html += '<th></th></tr>';

                // Контент
                for (var row = 0; row < result.rows.length; row++) {
                    html += '<tr data-id="' + result.rows[row].id + '">';
                    for (var column in result.rows[row]) {
                        // html += '<td>' + result[row][column] + '</td>'
                        html += settings.columns[column].render(result.rows[row]);
                    }
                    html += '<td>';
                    if (settings.controls.isEdit) html += '<a href="#" class="jsgrid-edit"><i class="ficon-cog"></i></a>';
                    if (settings.controls.isDelete) html += '<a href="#" class="jsgrid-delete"><i class="ficon-cancel"></i></a>';
                    html += '</td></tr>';
                }
                html += '</table></div>';
                container.append(html);
            });
        },
        handlers: function (container, settings) {
            container.on('click', '.jsgrid-delete', function (e) {
                e.preventDefault();
                settings.id = $(this).closest('tr').attr('data-id');
                var request = ajax.destroy(settings);
                request.done(function (result) {

                });
            });
        }
    }

    $.fn.jsGrid = function (options) {
        // Если плагин ещё не проинициализирован
        if (!this.data('jsgrid')) {
            settings = $.extend(true, {}, defaults, options);
            this.data('jsgrid', settings);
            // Обработчики событий
            dom.handlers(this, settings);
        }
        else settings = this.data('jsgrid');

        dom.render(this, settings);
    }

})(jQuery);

destus 17.07.2016 18:09

PMaster,
Нужно всего лишь научиться дебажиться. На строке 2 запускается jsGrid плагина, далее он собирается какие-то настройки и запускает метод dom.render, передавая туда контекст и эти самые настройки. На строке 77 запускается какой-то get запрос, и в этот самый $.get вторым параметром попадает объект настроек, среди которых есть функции. Далее мы сходу попадаем сюда http://s33.radikal.ru/tempfiles/23e5.../-88693455.png и видим комментарий: если значение - функция, то она запускается и её результат возвращается. Теперь мы попадаем на строку 26 и вылетаем с ошибкой.

PMaster 17.07.2016 20:25

Цитата:

Сообщение от destus (Сообщение 422362)
PMaster,
На строке 77 запускается какой-то get запрос, и в этот самый $.get вторым параметром попадает объект настроек, среди которых есть функции. Далее мы сходу попадаем сюда http://s33.radikal.ru/tempfiles/23e5.../-88693455.png и видим комментарий: если значение - функция, то она запускается и её результат возвращается. Теперь мы попадаем на строку 26 и вылетаем с ошибкой.

Спасибо. Теперь ясно. В ajax запрос нужно передавать только данные. Я для простоты весь объект настроек ему давал, поэтому render запускался сам по себе.


Часовой пояс GMT +3, время: 11:04.