本地数组更改时如何重新渲染 meteor blaze 模板?
How to re-render meteor blaze template when local array changes?
在过去 2 年多的时间里,我与 AngularJS 一起工作了很多,现在开始接触 MeteorJS 1.2,blaze 模板层的某些方面对我来说感觉很不直观,但可能有一个简单的解决方案。
我想要一个 "Create poll" 表单,其中包含以下字段:
- 问题,文本字段
- 投票选项,文本字段
- 添加选项、按钮
- 选项列表,基于本地
options
数组的 <li>
的转发器
- 列表项有一个删除按钮
本质上,我希望能够填充投票选项字段,单击 "add option" 并以只读方式(纯文本)在投票选项文本字段下方的列表转发器中呈现此选项。
我目前的问题是,如果不使用 ReactiveArray 之类的东西,当我将项目推送到本地数组变量 options
.
时,blaze 模板不会重新呈现
解决这个问题的正确方法是什么?
代码如下:
poll.create.html
模板:
<template name="pollCreate">
<form class="form form--create">
<section class="form__section">
<!-- Question Field -->
<input class="form__field" type="text" name="question" required>
<!-- Poll Options -->
<ul class="form__list">
<!-- Poll option form field -->
<li class="form__list-item form__list-item--creator">
<input class="form__field" type="text" name="pollOption">
<button class="form__button--add" type="button">+</button>
</li>
<!-- Render the options added above -->
{{#each option in optionList}}
<li class="form__list-item--option" data-index="{{option.index}}">
<span class="form__list-item-value">{{option.label}}</span>
<button type="button" class="form__button--delete">×</button>
</li>
{{/each}}
</ul>
</section>
<button class="form__button--submit" type="submit">Create Poll</button>
<button class="form__button--reset" type="reset">Clear Fields</button>
</form>
</template>
poll.create.client.js
(Polls = new Mongo.Collection("polls")
在服务器文件中)
// Setup
Template.pollCreate.onCreated(function () {
// Local poll variable to capture the options in.
this.options = [
{ index: 0, label: 'BurgerBurger' },
{ index: 1, label: 'BetterBurger' }
];
});
// Events
Template.pollCreate.events({
/**
* Adds an option to the local array for saving as part of the submit in the Posts.insert call.
* @param event
* @param instance
*/
'click .form__button--add': function ( event, instance ) {
event.preventDefault();
// Get current option element
var option = instance.find('[name="pollOption"]');
// Store in a local array
instance.options.push({
index: instance.options.length,
label: option.value
});
// Clear field so it's ready for another option
option.value = '';
},
/**
* Delete an existing option.
* @param event
* @param instance Template.instance
*/
'click .form__button--delete': function ( event, instance ) {
event.preventDefault();
var listItemElement = event.target.parentNode;
var itemIndex = instance.$(listItemElement).data('index');
// Delete option from reactive source array
instance.options.splice(itemIndex, 1);
},
/**
* Submit the Poll Create form which will run Polls.insert with the question and options
* @param event
* @param instance
*/
'submit .form--create': function ( event, instance ) {
event.preventDefault();
var question = instance.find('[name="question"]');
var options = instance.options;
var poll = {
question: question.value,
options: options
};
Polls.insert(poll);
}
});
// Helpers
Template.pollCreate.helpers({
optionList: function () {
const instance = Template.instance();
return instance.options;
}
});
我可以看到 instance.options
数组值在我将选项推入和切出时发生变化,但它似乎没有重新呈现模板,选项列表也从未改变。
我做错了什么?
每当您希望 ui 响应式更新时,您需要有两件事,(1) 响应式数据源和 (2) 响应式上下文。
现在您已经获得了响应式上下文 - 这是模板助手 optionList
,它将在它引用的响应式数据源发生更改时重新呈现。问题是选项列表不是反应性数据源,它只是一个原始数组。所以当 Templace.instance().options
数组改变时,助手不知道重新渲染它。
修复非常简单 - 只需在反应结构 ReactiveVar
或 ReactiveDict
中使用 Meteor 的 built 之一,使 Template.instance.options
成为反应数据源,或者通过使用 MiniMongo
。 ReactiveArray
你提到的也可以工作 - 我相信这是社区维护的而不是核心包,但它是相同的想法。
这里 qui最简单的解决方案是将整个数组保存为一个 ReactiveVar
:
Template.pollCreate.onCreated(function(){
this.options = new ReactiveVar([
{ index: 0, label: 'BurgerBurger' },
{ index: 1, label: 'BetterBurger' }
]);
});
Template.pollCreate.helpers({
optionList({
return Template.instance().options.get();
})
});
应该可以了。
在过去 2 年多的时间里,我与 AngularJS 一起工作了很多,现在开始接触 MeteorJS 1.2,blaze 模板层的某些方面对我来说感觉很不直观,但可能有一个简单的解决方案。
我想要一个 "Create poll" 表单,其中包含以下字段:
- 问题,文本字段
- 投票选项,文本字段
- 添加选项、按钮
- 选项列表,基于本地
options
数组的<li>
的转发器 - 列表项有一个删除按钮
本质上,我希望能够填充投票选项字段,单击 "add option" 并以只读方式(纯文本)在投票选项文本字段下方的列表转发器中呈现此选项。
我目前的问题是,如果不使用 ReactiveArray 之类的东西,当我将项目推送到本地数组变量 options
.
解决这个问题的正确方法是什么?
代码如下:
poll.create.html
模板:
<template name="pollCreate">
<form class="form form--create">
<section class="form__section">
<!-- Question Field -->
<input class="form__field" type="text" name="question" required>
<!-- Poll Options -->
<ul class="form__list">
<!-- Poll option form field -->
<li class="form__list-item form__list-item--creator">
<input class="form__field" type="text" name="pollOption">
<button class="form__button--add" type="button">+</button>
</li>
<!-- Render the options added above -->
{{#each option in optionList}}
<li class="form__list-item--option" data-index="{{option.index}}">
<span class="form__list-item-value">{{option.label}}</span>
<button type="button" class="form__button--delete">×</button>
</li>
{{/each}}
</ul>
</section>
<button class="form__button--submit" type="submit">Create Poll</button>
<button class="form__button--reset" type="reset">Clear Fields</button>
</form>
</template>
poll.create.client.js
(Polls = new Mongo.Collection("polls")
在服务器文件中)
// Setup
Template.pollCreate.onCreated(function () {
// Local poll variable to capture the options in.
this.options = [
{ index: 0, label: 'BurgerBurger' },
{ index: 1, label: 'BetterBurger' }
];
});
// Events
Template.pollCreate.events({
/**
* Adds an option to the local array for saving as part of the submit in the Posts.insert call.
* @param event
* @param instance
*/
'click .form__button--add': function ( event, instance ) {
event.preventDefault();
// Get current option element
var option = instance.find('[name="pollOption"]');
// Store in a local array
instance.options.push({
index: instance.options.length,
label: option.value
});
// Clear field so it's ready for another option
option.value = '';
},
/**
* Delete an existing option.
* @param event
* @param instance Template.instance
*/
'click .form__button--delete': function ( event, instance ) {
event.preventDefault();
var listItemElement = event.target.parentNode;
var itemIndex = instance.$(listItemElement).data('index');
// Delete option from reactive source array
instance.options.splice(itemIndex, 1);
},
/**
* Submit the Poll Create form which will run Polls.insert with the question and options
* @param event
* @param instance
*/
'submit .form--create': function ( event, instance ) {
event.preventDefault();
var question = instance.find('[name="question"]');
var options = instance.options;
var poll = {
question: question.value,
options: options
};
Polls.insert(poll);
}
});
// Helpers
Template.pollCreate.helpers({
optionList: function () {
const instance = Template.instance();
return instance.options;
}
});
我可以看到 instance.options
数组值在我将选项推入和切出时发生变化,但它似乎没有重新呈现模板,选项列表也从未改变。
我做错了什么?
每当您希望 ui 响应式更新时,您需要有两件事,(1) 响应式数据源和 (2) 响应式上下文。
现在您已经获得了响应式上下文 - 这是模板助手 optionList
,它将在它引用的响应式数据源发生更改时重新呈现。问题是选项列表不是反应性数据源,它只是一个原始数组。所以当 Templace.instance().options
数组改变时,助手不知道重新渲染它。
修复非常简单 - 只需在反应结构 ReactiveVar
或 ReactiveDict
中使用 Meteor 的 built 之一,使 Template.instance.options
成为反应数据源,或者通过使用 MiniMongo
。 ReactiveArray
你提到的也可以工作 - 我相信这是社区维护的而不是核心包,但它是相同的想法。
这里 qui最简单的解决方案是将整个数组保存为一个 ReactiveVar
:
Template.pollCreate.onCreated(function(){
this.options = new ReactiveVar([
{ index: 0, label: 'BurgerBurger' },
{ index: 1, label: 'BetterBurger' }
]);
});
Template.pollCreate.helpers({
optionList({
return Template.instance().options.get();
})
});
应该可以了。