Как получить доступ к объекту запроса из помощника пользовательских рулей

Я использую руль с node.js и экспресс, и у меня есть собственный зарегистрированный помощник для отображения температуры, который я хотел бы иметь доступ к параметру запроса из URL-адреса страницы.

Концепция помощника заключается в том, чтобы автоматически обрабатывать преобразование Фаренгейта в Цельсия в зависимости от того, находится ли ?tempFormat=F или tempFormat=C в URL-адресе или нет. Вот псевдокод пользовательского помощника, который я хотел бы иметь:

hbs.registerHelper("formatTemp", function(temp) {
    if (query parameter says to use Fahrenheit) {
        temp = toFahrenheitStr(temp);
    }
    return temp;
});

Итак, я бы хотел, чтобы мой шаблон выглядел так:

{{#each temperatures}}
    <div class="row {{{stripes @index}}}"> 
        <div class="time">{{prettifyDate t}}</div>
        <div class="atticTemp">{{formatTemp atticTemp}}</div>
        <div class="outsideTemp">{{formatTemp outsideTemp}}</div>
        <div class="spacer"></div>
    </div>
{{/each}}

Сейчас я работаю над этой проблемой, вытаскивая request.query.tempFormat и помещая его в данные, переданные для рендеринга шаблона:

app.get('/debug', function(request, response) {
    var tempData = {
        temperatures: data.temperatures,
        units: request.query.tempFormat || "C"
    };
    response.render('debug', tempData);
});

И затем передать эти данные в шаблон:

{{#each temperatures}}
    <div class="row {{{stripes @index}}}"> 
        <div class="time">{{prettifyDate t}}</div>
        <div class="atticTemp">{{formatTemp atticTemp ../units}}</div>
        <div class="outsideTemp">{{formatTemp outsideTemp ../units}}</div>
        <div class="spacer"></div>
    </div>
{{/each}}

Но это кажется запутанным, потому что я должен передавать единицы измерения температуры в каждый вызов рендеринга шаблона, а затем помещать их в каждый шаблон, где я хочу, чтобы они использовались дисплеем температуры. Они уже сидят в объекте запроса. Итак, я пытаюсь понять, как получить доступ к объекту запроса из пользовательской вспомогательной функции руля? Таким образом, я мог сохранять код для каждого рендеринга и сохранять код в каждом шаблоне, а параметр запроса tempFormat автоматически применялся к любому использованию formatTemp в моих шаблонах.

Кто-нибудь знает, как получить доступ к объекту запроса из пользовательского помощника руля без использования глобального?


person jfriend00    schedule 01.09.2014    source источник
comment
В связи с этим, кто-нибудь знает, есть ли форум, на котором обсуждаются проблемы с рулями, где с большей вероятностью можно найти экспертов по рулям (поскольку по этому вопросу не было активности)?   -  person jfriend00    schedule 02.09.2014
comment
@raidendev - это не браузер, это сервер, на котором работает node.js, и он был бы в location.search, а не location.pathname, если бы это был браузер, и я стараюсь избегать использования глобальных переменных, чтобы у нескольких запросов не было проблем.   -  person jfriend00    schedule 03.09.2014


Ответы (3)


Сначала вам нужно назначить объект запроса локальному ответу, зарегистрировав промежуточное программное обеспечение в любом месте перед вашим маршрутом.

app.use(function(req,res,next){
    res.local.req = req;
    next();
})

Затем вы можете получить доступ к объекту запроса в вашем помощнике

<div class="atticTemp">{{formatTemp atticTemp ../req.query.tempFormat }}</div>
person Roland    schedule 21.01.2015
comment
может зависеть от версии, но мне пришлось использовать: { res.locals.req = req; } - person thomas; 25.03.2018

Handlebars всегда вызывает помощники с текущим контекстом, таким как this, поэтому вы можете вызывать блок с this, чтобы оценить блок в текущем контексте.

https://handlebarsjs.com/block_helpers.html#basic-blocks

Вы можете объединить ответ @Roland с этой функцией, чтобы ваш помощник определил правильный формат с одним параметром.

Сначала добавьте промежуточное ПО, чтобы ввести значение из запроса в контекст для рулей.

app.use(function(req, res, next){
    var tempUnits = this.req.query.tempFormat || 'C';
    this.locals.tempUnits = tempUnits;
    next();
})

Затем в вашей промежуточной функции вы можете использовать this.tempUnits для доступа к введенному вами значению.

hbs.registerHelper("formatTemp", function(temp) {
    var units = this.tempUnits;
    if (units == 'F') {
        temp = toFahrenheitStr(temp);
    }
    return temp;
});

Затем у вас может быть помощник с одним параметром, который получает данные из запроса.

<div class="atticTemp">{{formatTemp atticTemp}}</div>

Примечание. Вы можете добавить весь объект запроса, но будет чище, если промежуточное ПО введет нужное вам значение.

person duckbrain    schedule 08.07.2019
comment
это работает только в коде hbs верхнего уровня. Когда вы находитесь в другом контексте, например. #each контекст переключается, а переменная this представляет текущий повторяющийся элемент. В этих ситуациях res.locals недоступен в помощнике. - person lifeisfoo; 10.02.2020

Я использую пакет экспресс-рулей. Вы можете зарегистрировать помощников в его объекте конфигурации, как показано ниже. Немного отличается от вашего способа, но вы получите идею. Чтобы сократить вещи, я только что добавил второй параметр в вашу вспомогательную функцию (:

var exphbs  = require('express-handlebars');

app.engine('handlebars', exphbs({
    defaultLayout: 'layout',
    helpers : {
        formatTemp: function(temp, unit) {
            console.log(unit);
            if (unit=="F") {
                return temp;
            } else {
                return 32 + (temp* 9 / 5);
            }
        }
    }

структура данных контекста и использование одинаковы.

проверено.

person Mehmet AVŞAR    schedule 12.11.2014
comment
Извините, но это не помогает. У меня уже есть зарегистрированный помощник (это показано в моем вопросе). И единицы должны поступать из файла cookie или параметра запроса, а не из шаблона. - person jfriend00; 12.11.2014
comment
вам просто нужно добавить второй параметр (единицу измерения) к уже зарегистрированной вспомогательной функции. источник значения здесь не при чем. откуда бы вы ни взяли значение единиц (C|F), все, что вам нужно сделать, это передать это значение в контекст данных представления (в качестве второго параметра функции res.render), а затем использовать его в вызове помощника. - person Mehmet AVŞAR; 13.11.2014
comment
иоу, вы в шаге от решения. если вы меняете вызов помощника на {{formatTemp outsideTemp ../units}}, то ваш помощник должен получить 2 параметра... вот и все. - person Mehmet AVŞAR; 13.11.2014
comment
просто попробуй так: hbs.registerHelper("formatTemp", function(temp, unit) { if (unit === "F") { temp = toFahrenheitStr(temp); } return temp; }); - person Mehmet AVŞAR; 13.11.2014