过去几周我一直在尝试使用Knockout.js映射和组件,坦白说,它只是糟透了。我发誓我错过了一些让一切都运转良好的魔术片,因为目前我试图用它制作的所有东西都感觉非常脱节和杂乱,因此,大多数都是无功能的。
我已经阅读了文档,虽然几乎没有满足或帮助。
我有一个主视图模型,但它不是这个故事的明星。这是我正在尝试构建的可重用组件。我们称之为TweetViewModel
。此组件取决于params.action
是设置为“创建”还是“显示”,将允许用户输入有关推文的信息,或将其显示给他们:
define(['knockout','ko.mapping', 'jquery', 'text!components/tweet/tweet.html'], function(ko, koMapping, $, htmlString) {
function TweetViewModel(params) {
var self = this;
self.tweet = params.tweet;
self.action = params.action;
self.tweetUrl = ko.observable();
self.tweetUrl.subscribe(function(value) {
var valueOfTwitterUrlField = value;
// Check that the entered URL contains 'twitter' before sending a request (perform more thorough validation serverside)
if (valueOfTwitterUrlField.indexOf('twitter.com') !== -1) {
var explodedVals = valueOfTwitterUrlField.split('/');
var id = explodedVals[explodedVals.length - 1];
$.ajax('/myproj/create/retrievetweet/' + id, {
dataType: 'json',
type: 'GET',
success: function (response) {
}
});
}
// Allow default action
return true;
});
}
return { viewModel: TweetViewModel, template: htmlString };
});
<!-- ko if: action == 'show' -->
<div class="card twitter-card">
</div>
<!-- /ko -->
<!-- ko if: action == 'create' -->
<div class="card twitter-card create">
<label>Tweet URL</label>
<input type="url" name="tweet_url" id="tweet_url" data-bind="textInput: tweetUrl" />
<hr/>
<p>Alternatively, if the tweet is no longer available, enter the tweet information below</p>
<div class="tweeter-details">
<img src="" />
<span class="tweeter-screen-name" data-bind="text: tweet.tweet_user_screen_name"></span>
<label>Username</label>
<input type="text" class="tweeter-name" data-bind="value: tweet.tweet_user_name" />
</div>
<textarea class="tweet-text" data-bind="text: tweet.tweet_text"></textarea>
<div class="date-input">
<datetime params="value: tweet.tweet_created_at, type: 'datetime'"></datetime>
</div>
</div>
<ul class="tweet-images-list" data-bind="template: { name: 'tweet-images-template', foreach: tweet.images }">
</ul>
<div class="tweet-images-details"></div>
<!-- /ko -->
<script type="text/html" id="tweet-images-template">
</script>
通过以下HTML调用此模板:
<tweet params="action: 'create', tweet: tweetData"></tweet>
action
是我感兴趣的模板的哪个部分,tweet: tweetData
是我希望我的父视图模型与我的组件进行通信的方式。 tweetData
可能是具有以下属性的对象:
self.tweet = {
tweet_id: ko.observable(),
tweet_text: ko.observable(),
tweet_user_name: ko.observable(),
tweet_user_screen_name: ko.observable(),
tweet_created_at: ko.observable(),
tweet_parent_id: ko.observable(),
images: ko.observableArray()
}
目前,我主要关心的是展示事物的“创造”方面。简单地显示推文数据非常简单。具体来说,我想知道我的组件上的输入/输出应该如何工作。
1)如果我将一些JSON / JS对象/数据集从我的parentviewmodel传递到我的组件,为什么我需要重新定义组件中的observable?
我的意思是:
self.tweet = params.tweet;
为什么这有必要?如果我不这样做,并尝试在我的模板(或tweet.tweet_user_name
)上引用params.tweet.tweet_user_name
,我会收到以下错误:
ReferenceError: tweet is not defined
为什么我的模板不知道传递给组件构造函数的变量?回想一下,我的构造函数定义如下:
function TweetViewModel(params) { //SNIP
如果我必须在我的组件上重新定义我的对象,那么对其进行的更改是否会映射回parentviewmodel上的tweetData
?
2)当我有多个输入源和多个输出源时,如何使它们与挖空映射保持一致,而不会对未定义的属性进行调整而不观察更改?
如果您查看我的组件,您可以看到我有两个输入源来获取推文信息。一个是来自params
的数据,另一个是我向服务器发出的AJAX请求,用于从Twitter API获取数据。
这些数据源看起来完全不同。理想情况下,我希望我的“模型”看起来好像我已经在上面定义了一个'推文'对象,其中有7个可观察属性,范围从images
到tweet_id
。我的parentviewmodel上来自tweetData
的数据看起来应该是这样的,但是当我期望创建一条推文时它可能是空的。来自我的AJAX请求的数据将是我需要格式化的twitter API的原始响应。
具体来说,我有以下情况和问题:
tweetData
始终包含我首选模型的信息或大纲。 这通常发生在完全创建推文时,除了我父视图模型上的可观察对象之外不存在。我传递给我的组件的变量是我期望由我的组件上的Knockout映射填充的东西 - 我不需要传入一个已经格式化了所有属性的空对象。
params.tweet
值时,它实际上不会覆盖self.tweet
中的值,并且它不会更新我的数据绑定。考虑以下代码:
self.tweet.tweet_text = ko.observable("foo")
$.ajax('/myproj/create/retrievetweet/' + id, {
dataType: 'json',
type: 'GET',
success: function (response) {
self.tweet = {
tweet_id: ko.observable(response.id),
tweet_text: ko.observable(response.text),
tweet_user_name: ko.observable(response.user.name),
tweet_user_screen_name: ko.observable(response.user.screen_name),
tweet_created_at: ko.observable(response.created_at),
tweet_parent_id: ko.observable(response.in_reply_to_status_id),
images: ko.observableArray(response.entities.media)
}
}
});
这个成功回调实际上不会因为某些原因在我的模板上设置任何内容。我绑定到tweet.tweet_text
的文本绑定仍会显示“foo”,即使在我收到有效的响应之后也应该按照我上面的定义重置它。
使用敲除映射与来自服务器的响应更令人厌恶。没有办法将我要观察的属性列入白名单,我只能通过ignore
选项设置列入黑名单 - 考虑Twitter返回多少数据,这是手动忽略的很多属性!此外,Twitter返回的属性名称与我尝试使用的属性名称不匹配(见上文),所以我甚至不确定淘汰映射是否适合这里。
3)我是如何错误地使用Knockout.js + mapping +组件的?我试图创建的组件的起始结构是什么?
我在这里结束了我的智慧,我很高兴地尝试向我投掷的所有建议。理想情况下,我希望尽可能多地回答我的问题。
答案 0 :(得分:1)
组件有自己的视图模型,因为通过设计它们是可重用的,并且可以在具有不同视图模型的不同应用程序中使用。如果要引用主视图模型,请将其作为参数传递。
不要重新分配包含绑定的observable的绑定的observable或变量。您可以使用普通函数调用(例如self.tweet.tweet_id(newValue)
)设置它们的值,但如果使用等号,则通常会抛出绑定变量。
如果你想将值列入白名单,我想你也可以创建和分配变量。 ko.mapping
不会为您节省任何费用。