我有x-editable在Meteor 0.7.2中工作,但自升级到0.8.0后,它不再正确呈现。我倾向于最终得到一堆空标签。这是令人沮丧的,因为数据存在,而不是在渲染函数被触发时。
<template name="clientPage">
<header>{{> clientPageTitleUpdate}}</header>
</template>
<template name="clientPageTitleUpdate">
<h1><span class="title-update editable" data-type="text" data-pk="{{_id}}" data-name="title" data-value="{{title}}">{{title}}</span></h1>
</template>
Template.clientPageTitleUpdate.rendered = function() {
console.log(this.$(".title-update").text());
// set up inline as defaule for x-editable
$.fn.editable.defaults.mode = 'inline';
$(".title-update.editable:not(.editable-click)").editable('destroy').editable({
url: "empty",
toggle: "dblclick",
success: function (response, newValue) {
// update value in db
var currentClientId = $(this).data("pk");
var clientProperties = { title: newValue };
Clients.update(currentClientId, {$set: clientProperties}, function(error) {
if (error) {
Errors.throw(error.message)
}
});
}// success
});
}
我已经尝试了“新”渲染方法,将其嵌入到另一个模板中,如here所述,它似乎也无效。
现在使用x-editable的最佳方法是什么,渲染只会触发一次并且无法确保数据存在。
我正在使用Iron Router,我的模板没有嵌入{{#each}}块中,这似乎是新渲染模型的基本解决方案。
此问题与关于x-editable in a meteor template的旧主题相关。
任何帮助都会在这里得到超级赞赏。我很茫然。感谢
答案 0 :(得分:8)
编辑:现在在Meteor 0.8.3中更容易实现:
模板:
<template name="docTitle">
<span class="editable" title="Rename this document" data-autotext="never">{{this}}</span>
</template>
代码:
Template.docTitle.rendered = ->
tmplInst = this
this.autorun ->
# Trigger this whenever data source changes
Blaze.getCurrentData()
# Destroy old editable if it exists
tmplInst.$(".editable").editable("destroy").editable
display: ->
success: (response, newValue) -> # do stuff
为了最有效,请确保可编辑模板的数据上下文仅为正在编辑的字段,如上面的{{> docTitle someHelper}}
示例所示。
Meteor 0.8.0至0.8.2的过时信息
我还必须这样做但不确定在我的应用中使用全局帮助器。所以我试图通过改变可编辑的行为来实现它。
在perusing the docs和来源之后,需要完成的主要事项是:
display
功能,以便reactivity of text updated by Meteor doesn't break 这是代码(为Coffeescript道歉):
Template.foo.rendered = ->
container = @$('div.editable')
settings =
# When opening the popover, get the value from text
value: -> $.trim container.text()
# Don't set innerText ourselves, let Meteor update to preserve reactivity
display: ->
success: (response, newValue) =>
FooCollection.update @data._id,
$set: { field: newValue }
# Reconstruct the editable so it shows the correct form value next time
container.editable('destroy').editable(settings)
container.editable(settings)
这很难看,因为它在设置新值后会破坏并重新创建弹出框,以便表单字段从正确的值更新。
经过一些更多的逆向工程后,我找到了一种更简洁的方法,不会破坏可编辑的。加迪是正确的container.data().editableContainer.formOptions.value
与此有关。这是因为这个值是set after the update,因为x-editable认为它现在可以缓存它。好吧,它不能,所以我们用原始函数替换它,所以值继续从文本字段更新。
Template.tsAdminBatchEditDesc.rendered = ->
container = @$('div.editable')
grabValue = -> $.trim container.text() # Always get reactively updated value
container.editable
value: grabValue
display: -> # Never set text; have Meteor update to preserve reactivity
success: (response, newValue) =>
Batches.update @data._id,
$set: { desc: newValue }
# Thinks it knows the value, but it actually doesn't - grab a fresh value each time
Meteor.defer -> container.data('editableContainer').formOptions.value = grabValue
注意:
$.trim
取自the default behavior to render value 我将尝试在未来更加简洁,等待Meteor更好地支持数据的反应性。
答案 1 :(得分:5)
更新了Meteor 0.8.3 +
这涵盖了我的所有案例(见下面的代码)。这使用非常细粒度的反应性,只有在指定的值发生变化时才会更新x-editable实例。
<强>模板:强>
<!-- once off for your entire project -->
<template name="xedit">
{{> UI.contentBlock}}
</template>
<!-- per instance -->
<template name="userInfo">
{{#xedit value=profile.name}}<a>{{profile.name}}</a>{{/xedit}}
</template>
客户端Javascript(适用于Meteor 0.8.3 +):
// once off for your entire project
Template.xedit.rendered = function() {
var container = this.$('*').eq(0);
this.autorun(function() {
var value = Blaze.getCurrentData().value;
var elData = container.data();
if (elData && elData.editable) {
elData.editable.setValue(value, true);
// no idea why this is necessary; xeditable bug?
if (elData.editableContainer)
elData.editableContainer.formOptions.value = elData.editable.value;
}
});
}
// per instance; change selector as necessary
Template.userInfo.rendered = function() {
// Note you don't need all the :not(.editable) stuff in Blaze
this.$('a').editable({
success: function(response, newValue) {
// according to your needs
var docId = $(this).closest('[data-user-id]').attr('data-user-id');
var query = { $set: {} }; query['$set']['profile.username'] = newValue;
Meteor.users.update(docId, query);
}
});
});
您可以在http://doingthiswithmeteor.com/处看到它(两个窗口打开)。您需要登录,但请尝试更改&#34; me&#34;上的任何信息。页。
刚刚实施了这个......仍在做一些测试,但欢迎反馈。这取代了我之前的帮助程序。
答案 2 :(得分:1)
如果安德鲁的回答对您有用,并且您有很多这样的字段,您可能会发现使用函数创建所需模板很方便。这是一个例子
<template name="main">
<div style="height:200px"></div>
<div class="container">
<div class="jumbotron">
{{#each editables}}
{{> editable1}}
{{> editable2}}
{{/each}}
</div>
</div>
</template>
<template name="editable1">
<p id="{{id}}" data-type="textarea" data-placeholder="Enter text" data-emptytext="Click to enter text" data-rows="4">{{content}}</p>
</template>
<template name="editable2">
<p id="{{id}}" data-type="textarea" data-placeholder="Enter text" data-emptytext="Click to enter text" data-rows="4">{{content}}</p>
</template>
并在js:
Template.main.editables = function(){
return Objects.find({});
};
function xeditFactory(collection, template, field){
template.content = function(){ return this[field]; };
template.id = function(){ return 'xedit_'+this._id+'_'+field; };
template.rendered = function(){
var container = this.$('#xedit_'+this.data._id+'_'+field);
console.log(container);
var grabValue = function() {
return $.trim(container.text());
};
return container.editable({
value: grabValue,
display: function() {},
success: (function(_this) {
return function(response, newValue) {
var set = {};
set[field]=newValue;
collection.update(_this.data._id, {$set:set});
return Meteor.defer(function() {
return container.data('editableContainer').formOptions.value = grabValue;
});
};
})(this)
});
};
}
xeditFactory(Objects, Template.editable1, 'field1');
xeditFactory(Objects, Template.editable2, 'field2');
答案 3 :(得分:1)
另一个使用iron-router和管理Collection2验证的实现:
控件
div(id="text" class="editable" data-type="text" data-pk="#{_id}" data-name="address" data-value="#{address}" data-context="Buildings") #{address}
JS代码:
setTimeout( -> #needed to work with iron-router
$(".editable").editable
placement: "auto top"
display: ->
success: (response, newValue) ->
newVal = {}
oldVal = $.trim $(this).data("value")
name = $(this).data("name")
newVal[name] = newValue
eval($(this).data("context")).update $(this).data("pk"), $set: newVal
, (error) ->
Notifications.error error.message
Meteor.defer -> $(".editable[data-name=" + name + "]").data('editableContainer').formOptions.value = oldVal
console.log "set new value to " + newValue
Session.set "text", newValue
,500)
我找不到自动设置数据上下文的方法。我相信这应该不是很困难。欢迎任何帮助!
答案 4 :(得分:1)
根据安德鲁的回答,我能够让这个为我工作。它不在coffeescript中,我认为根据Meteor文档,Blaze.getCurrentData()现在可能是Blaze.getData()。
模板:
<template name="objective">
<p id="objective" class="editable" data-type="textarea" data-placeholder="Enter text" data-emptytext="Click to enter text" data-rows="4">{{objective.value}}</p>
</template>
代码:
Template.objective.rendered = function(){
var self = this;
this.autorun(function(){
data = Blaze.getData();
self.$("#objective.editable").editable("destroy").editable({
placement: "bottom",
display: function(){},
success: function(response, newValue){
var insert = {
"contract_id":data._id,
"value": newValue
};
Meteor.call('update_objective', insert);
}
});
});
};
我可以做些改进,我很高兴听到它们,但我花了很多时间来处理糟糕的咖啡因翻译(一直告诉我一直使用返回),所以我想添加另一个例子。
答案 5 :(得分:0)
这是我的简化方法,基于gadicc的帖子(使用Meteor 0.9.3测试)。
我们假设有一个MyDocuments
集合,通过documentList
模板呈现。集合中的每个文档都有title
字段,我们要使用xedtiable进行编辑。
<强> document.html 强>
<template name="documentList">
{{#each documents}}
{{>document}}
{{/each}}
</template>
<template name="document">
<p>Title: {{>xeditable titleOptions}}</p>
</document>
<强> document.js 强>
Template.document.titleOptions = function () {
return {
// We need to specify collection, id and field to autoupdate MongoDb
collection: MyDocuments,
id: this._id,
field: 'title',
value: this.title
}
}
<强> xeditable.html 强>
<template name="xeditable">
<span class="xeditable">{{value}}</span>
</template>
<强> xeditable.js 强>
Template.xeditable.rendered = function () {
var container = this.$('*').eq(0);
if (!container.hasClass('processed')) {
container.addClass('processed');
var options = _.extend(this.data, {
// Default success function, saves document do database
success: function (response, value) {
var options = $(this).data().editable.options;
if (options.collection && options.id && options.field) {
var update = {};
update[options.field] = value;
options.collection.update(options.id, {
$set: update
});
}
}
});
container.editable(options);
}
this.autorun(function () {
var value = Blaze.getData().value;
var elData = container.data();
if (elData && elData.editable) {
elData.editable.setValue(value, true);
// no idea why this is necessary; xeditable bug?
if (elData.editableContainer)
elData.editableContainer.formOptions.value = elData.editable.value;
}
});
}