Как разумно обрабатывать выборки в ractivejs?

Мы хотим (пере)создать веб-приложение. Мы хотели бы сделать его изоморфным, чтобы сервер мог отображать одни и те же шаблоны, но модель состояния javascript существовала бы и обрабатывала обновления. Я рассматриваю ractivejs и усы/рули как один из довольно многообещающих вариантов.

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

Например, у нас могут быть следующие данные

{
    "data": [{
        "firstName": "Joe",
        "lastName": "Bloggs",
        "travelDocument": "PASS BOOK",
        "issueCountry": "US",
        "issueState": "CA",
        "iterator_row_num": "0"
    },
    {
        "firstName": "Anne",
        "lastName": "Other",
        "travelDocument": "ID",
        "expiryDate": "2021-01-02",
        "issueDate": "1921-03-04",
        "iterator_row_num": "1"
    }],
    "fields": {
        "firstName": {
            "type": "text",
            "isList": false,
            "isDate": false
        },
        "lastName": {
            "type": "text",
            "isList": false,
            "isDate": false
        },
        "travelDocument": {
            "type": "list",
            "possibleValues": [{
                "name": "Passport",
                "dependentFields": [{
                    "name": "Issue Country",
                    "type": "list",
                    "possibleValues": [{
                        "name": "\u00c5land",
                        "value": "AX"
                    },
                    {
                        "name": "Finland",
                        "value": "FI"
                    },
                    {
                        "name": "Sweden",
                        "value": "SV"
                    },
                    {
                        "name": "United States",
                        "dependentFields": [{
                            "name": "Issue State",
                            "type": "list",
                            "possibleValues": [{
                                "name": "Alaska",
                                "value": "AL"
                            },
                            {
                                "name": "California",
                                "value": "CA"
                            },
                            {
                                "name": "New York",
                                "value": "NY"
                            }],
                            "isList": true,
                            "isDate": false,
                            "fieldName": "issueState"
                        }],
                        "value": "US"
                    }],
                    "isList": true,
                    "isDate": false,
                    "fieldName": "issueCountry"
                },
                {
                    "name": "Expiry Date",
                    "type": "date",
                    "isList": false,
                    "isDate": true,
                    "fieldName": "expiryDate"
                }],
                "value": "PASS BOOK"
            },
            {
                "name": "ID Card",
                "dependentFields": [{
                    "name": "Expiry Date",
                    "type": "date",
                    "isList": false,
                    "isDate": true,
                    "fieldName": "expiryDate"
                },
                {
                    "name": "Issue Date",
                    "type": "date",
                    "isList": false,
                    "isDate": true,
                    "fieldName": "issueDate"
                }],
                "value": "ID"
            }],
            "isList": true,
            "isDate": false
        }
    }
}

У меня были некоторые проблемы с элементами <select> для полей типа списка. То, что я хотел сделать в шаблоне, было примерно таким:

{{#data}}
    <input type="text" value="{firstName}" name="firstname[{{iterator_row_num}}]" />
    <input type="text" value="{lastName}" name="lastname[{{iterator_row_num}}]" />
    <select name="travelDocument[{{iterator_row_num}}]">
        {{#fields.travelDocument.possibleValues}}
            <option value="{{value}}"
                {{#if value == travelDocument }}
                    selected
                {{/if}}
            >{{name}}</option>
        {{/fields.travelDocument.possibleValues}}
    </select>
    {{#fields.travelDocument.possibleValues}}
        {{#if value == travelDocument}}
            dependent fields here
        {{/if}}
    {{/fields.travelDocument.possibleValues}}
{{/data}}

Но усы не позволяют, если со сравнениями. Я попытался добавить внутренний счетчик в свою модель данных и функцию приращения в начале каждого цикла. Эта функция в основном просматривала поля и добавляла/обновляла логическое свойство isCurrent для каждого возможного значения на основе текущих данных. Это работает в PHP, но тогда мне пришлось повторять свои функции увеличения в слое js. И я не могу заставить его работать. Кажется, все строки устанавливаются на основе первых для зависимых полей.

Тогда мой шаблон выглядел примерно так:

{{initLoop}}
{{#data}}
    {{advanceLoop}}
    <input type="text" value="{firstName}" name="firstname[{{iterator_row_num}}]" />
    <input type="text" value="{lastName}" name="lastname[{{iterator_row_num}}]" />
    <select name="travelDocument[{{iterator_row_num}}]">
        {{#fields.travelDocument.possibleValues}}
            <option value="{{value}}"
                {{#isCurrent }}
                    selected
                {{/isCurrent}}
            >{{name}}</option>
        {{/fields.travelDocument.possibleValues}}
    </select>
    {{#fields.travelDocument.possibleValues}}
        {{#isCurrent}}
            {{#dependentFields}}
                dependent fields here
            {{/dependentFields}}
        {{/isCurrent}}
    {{/fields.travelDocument.possibleValues}}
{{/data}}

У меня есть свойства indexN (целое число) и fixedIndex (логическое) в моей модели данных. Функция initLoop просто устанавливает indexN в -1.

Затем у меня есть функции, похожие на:

data._set_current_name = function() {
    this._currentName = false;
    if( this.data[this.indexN] !== undefined ) {
        this._currentName = this.data[this.indexN];
    }
    for( var field_id in this.fields ) {
        this._update_field_values(field_id, this.fields[field_id]);
    }
};
data._get_current_val = function(field_id) {
    var currentVal = '';
    if( false !== this._currentName && this._currentName[field_id] !== undefined ) {
        currentVal = this._currentName[field_id];
    }
    return currentVal;
};
data._update_field_values = function(field_id, field) {
    var currentVal = this._get_current_val(field_id);
    switch( field.type ) {
        case 'list':
            if( field.possibleValues ) {
                for( var posVal_i in field.possibleValues ) {
                    var posVal = field.possibleValues[posVal_i];
                    posVal.isCurrent = ( posVal.value === currentVal );
                    if( posVal.dependentFields ) {
                        for( var depField_i in posVal.dependentFields ) {
                            var depField = field.possibleValues[posVal_i].dependentFields[depField_i];
                            this._update_field_values(depField.fieldName, field.possibleValues[posVal_i].dependentFields[depField_i]);
                        }
                    }
                }
            }
            break;
        default:
            field.currentValue = currentVal;
            break;
    }
};
data.advanceNameLoop = function() {
    if( !this._fixedCounters ) {
        ++this.indexN;
    }
    this._set_current_name();
    return '';
};

Мы также хотим, чтобы он автоматически обновлял отображаемые зависимые поля при изменении значения «родительского» поля. Попытался добавить наблюдателя на ractive стороне, который устанавливает индексы для текущей строки, но он не держится полностью. Кроме того, изменение выбора, похоже, даже не вызывает его, тогда как изменение текстового поля вызывает? (Пытался с наблюдателем как на конкретном выборе, так и на .*, чтобы получить все поля).

Мой наблюдатель выглядел так:

names.observe('data.*.*', function(newValue, oldValue, keyPath){
    var pathParts = keyPath.split('.');
    this.viewmodel.data.setNameIndexes(pathParts[2]);
});

setNameIndexes это:

data.setNameIndexes = function(nameIndex) {
    this.indexN= nameIndex;
    this._fixedCounters = true;
};

Я даже вдоль правильных линий здесь? Как следует обрабатывать массив данных для нескольких полей. Учитывая, что некоторые поля (например, страна) могут иметь множество возможных значений, я действительно хочу избежать отдельной копии всего поля для каждой строки данных. Это кажется странным, если это не лучший способ обработки выбора в усах / ractive

(Примечание: это упрощенная версия того, что у меня есть: у нас есть категоризация данных, поэтому у меня есть двойной индекс (категория, а затем имя) и многие другие поля. Из-за этого в приведенном выше могут быть небольшие ошибки)


person Adam    schedule 08.06.2016    source источник


Ответы (1)


Вам не нужно вручную устанавливать выбранный атрибут в теге с помощью ractive. См. часть об элементах <select> здесь: http://docs.ractivejs.org/latest/two-way-binding

Кратко взглянув на ваш JSON вверху и на то, что вы пытаетесь сделать, это должно сделать это:

{{#each data}}
    ...
    <select name="travelDocument{{iterator_row_num}}" value="{{travelDocument}}">
        {{#each possibleValues}}
            <option value="{{value}}">{{name}}</option>
        {{/each}}
    </select> 
{{/each}}

Это позволит синхронизировать data[i].travelDocument со значением поля выбора.

Что касается второй части вашего вопроса, отображение зависимых полей на основе выбранного файла travelDocument...

    {{#each fields.travelDocument.possibleValues}}
        {{#if value == travelDocument}}
            {{#each dependentFields}}
                I am a {{type}} named {{name}} <!-- you get the point -->
            {{/each}}
        {{/if}}
    {{/each}}

Есть несколько способов сделать это, но это должно помочь вам начать.

person PersonThing    schedule 15.06.2016