1

我一直在搜索,发现与我的问题有些相似,但没有一个与我正在尝试做的完全匹配(或者至少,这些解决方案对我不起作用)。我对 Durandal 真的很陌生,所以我几乎不知道从哪里开始完成这项工作。我正在开发一个测试应用程序,我有一个数据绑定的 div 来显示 html,如下所示:

视图上的数据绑定

<div class="active-document-text" id="document-text" data-bind="html: documentBody">

在视图模型的 javascript 中,我让它使用 AJAX 调用获取外部 HTML 文件。它工作正常并正确绑定到视图,显示文档。我的问题是外部 HTML 中也会有一个或多个数据绑定:

外部.html

Lorem ipsum dolor 
<div class="selectable" id="selectable-1"
 data-bind="event: { click: $parent.onmouseClick }" >
sit amet, consectetur adipiscing</div> elit.
Integer nec odio. Praesent libero. Sed cursus ante dapibus diam.
Sed nisi. Nulla quis sem at nibh elementum imperdiet.

我想知道如何设置它,以便它将这些实例数据绑定到当前视图模型以在那里处理。这个想法是有一个可选择的文本区域(简单的鼠标悬停突出显示),并将其与当前选定的索引进行比较。更简单的解释是,它类似于提供句子的应用程序,用户将单击名词类别,然后选择句子中的名词。如上例所示,可选择区域可以是文本中的任何位置。我已经能够让它呈现所有的 html,但未能成功地让数据绑定工作。我已经尝试根据动态生成的元素的淘汰数据绑定在它之后应用 ko.applyBindings(),但我会收到一个未定义的路由器错误,我也尝试过创建一个传递数据的组合,比如将动态 html 插入到 durandal 视图中,看起来外部 html 会有它自己的 .js 模型/视图模型。我会以完全错误的方式解决这个问题吗?也许过于复杂了?最初,我们将它分解为一个模型,其中每个文本部分都有一个可选择的属性,但分解相当大的文档和 HMTL 格式的噩梦真的很笨重,所以我试图找到一个更优雅的解决方案。我感谢您的帮助!

编辑

以下问题对此问题进行了扩展: 将事件绑定合并到外部 html 文件中所需的长 div 标记对可能是文档创建者的非开发人员不友好。我目前已经让它再次通过 AJAX 调用获取 html 文件,然后用长 div 标签替换一个简单的自定义“[selectable]”标签,并将其存储在一个可观察对象中,但我仍然不确定如何将它与绑定到当前视图。

这是它试图让它工作的当前外观。我在特别重要的行的开头添加了双星号。

风景:

<h3 data-bind="html: displayName"></h3>
<div class="document-analysis document-analysis-border">
    <span class="title-bar">Analyze Documents</span>
    <img src="./assets/images/arrow_minimize.jpg" class="minimize-button" />
    <div class="container">
        <div class="document-bar">
            <span class="title">Documents to Analyze</span><br />
            <img class="arrow-up" src="./assets/images/arrow_up.jpg" alt="Up Arrow" />
            <div data-bind="foreach: documentData()" class="documents scroll-bar">
                **<div data-bind="event: { click: function () { $parent.changeDocument($data); } }, attr: { id: 'document-' + id }" class="document">
                    <img data-bind="attr: { alt: title }" src="./assets/images/document_image.gif" class="document-image" />
                    <span data-bind="text: title" class="document-name"></span>
                </div>
            </div>
            <img class="arrow-down" src="./assets/images/arrow_down.jpg" alt="Down Arrow" />
        </div>
        <div class="inner-container">
            <div class="active-document">
                **<!--<div class="scroll-bar text" id="document-text" data-bind="compose: { view: currentDocument().url, transition: 'entrance' }"></div>-->
                **<div class="scroll-bar text" id="document-text" data-bind="compose: { view: documentFormatted, transition: 'entrance' }"></div>
                <button class="submit">Submit</button>
            </div>
            <div data-bind="foreach: bucketData()" class="buckets">
                <div data-bind="event: { click: function () { $parent.changeBucket($data); } }" class="bucket">
                    <img data-bind="attr: { id: 'bucket-' + id, src: image, alt: title }" src="//:0" class="bucket-image" />
                    <span data-bind="text: title" class="bucket-name"></span>
                </div>
            </div>
        </div>
    </div>
</div>

单击新文档时,第一个标记的行调用 changeDocument() 函数。第二行和第三行是使外部文档正常工作的尝试。注释掉的 compose 可以正常工作,但我必须使用长标签以方便在 mouseOver 和 mouseOut 上突出显示文本。点击目前主要用于调试。如果他们单击其中一个存储桶(类别),然后单击外部文档中的可选区域,它会检查数据,如果他们为文本选择选择了正确的类别,他们就会获得积分。

这是相关的视图模型信息:

var vm = {
        displayName: 'Document Analysis',
        currentDocument: ko.observable(docAnalysisObj.documents[0]),
        documentData: ko.observableArray(docAnalysisObj.documents),
        documentFormatted: ko.observable(),

        $init: $init,
        activate: activate,
        onmouseOver: onmouseOver,
        onmouseOut: onmouseOut,
        mouseClick: mouseClick,
        changeDocument: changeDocument,
        canDeactivate: canDeactivate,
        viewAttached: viewAttached
    };
    return vm;

function changeDocument(newDocument) {
        var self = this;
        // If they clicked the same document, ignore and return
        if (!newDocument || (self.currentDocument() && self.currentDocument().id === newDocument.id)) {
            return;
        }

        // Set the id selector name
        var docElementSelector = '#document-' + newDocument.id;

        // Remove the highlight from the previous class if it exists
        if (self.currentDocument()) {
            $('#document-' + self.currentDocument().id).removeClass('document-selected');
        }
        // Set the document to the new one
        self.currentDocument(newDocument);
        // Use data service to pull the html into self.documentFormatted
        dataservice.getDocument(self.documentFormatted, self.currentDocument().url);

        // Highlight the new current document
        $(docElementSelector).addClass('document-selected');

    }

mouseOver 和 mouseOut 实际上只是在将鼠标悬停在可选区域上时添加和删除 CSS 类。changeDocument() 是我尝试使用以下数据服务对象加载 html 并处理 CSS 更改。

数据服务对象:

var getDocument = function (documentObservable, url) {
        documentObservable([]);

        if (!url) {
            console.log('Error: No url provided for document');
            documentObservable('<h1>Error: Document Not Found</h1>Document source was undefined.');
            return;
        }

        url = './app/views/' + url;

        var options = {
            url: url,
            type: 'GET',
            dataType: 'html',
            cache: false,
            error: queryFailed
        };

        return $.ajax(options)
            .then(querySucceeded);

        function querySucceeded(data) {
            console.log('Document \'' + url + '\' retrieval succeeded.');
            documentObservable(data);

            var currentID = 1;
            while (documentObservable().match(/\[selectable\]/g)) {
                documentObservable(documentObservable().replace('[selectable]', '<div class="selectable" selectID="' + currentID + '" data-bind="event: { mouseover: function () { $root.onmouseOver(' + currentID + '); }, mouseout: function () { $root.onmouseOut(' + currentID + '); }, click: function () { $root.mouseClick(' + currentID + '); } }">'));
                currentID++;
            }
        }

        function queryFailed(jqXHR, textStatus) {
            console.log('Error getting document ' + url + ': ' + textStatus);
            documentObservable('<h1>Error: Document Not Found</h1>' + textStatus);
        }

    };

数据服务是其中的关键。它加载 html 并将所有出现的 [selectable] 替换为将用于数据绑定的长标记。我还没有实现结束标签的替换,但这是一件简单的事情。div 使用自定义属性 selectID 而不是 ID 的原因是因为老板说使用 ID 是个坏主意,因为它们可以在文档中重复,而自定义属性不太可能出现。

和一个样本文件:

[selectable]
            &bull; This is a sample selectable area. This will be highlighted<br />
            when someone mouses over it.
            <br />[/selectable]

长 div 已替换为 [selectable] 标记,以使具有基本 HTML 技能的人更容易构建示例文档。

最终,目标是为创建文档的人提供一个易于使用的标签,而不必尝试将长标签粘贴到其中并跟踪其个人 ID。我想保持鼠标事件与视图模型相关联,因为它都是相同的活动(所有文档的分数将汇总在一起以获得最终分数)。从用户的角度来看,当他们将鼠标悬停在可选文本上时,它应该只是改变颜色(简单的 jQuery)。如果他们点击它,它会检查他们是否选择了正确的类别(我已经有了这个工作)。我当前的问题是进行文本替换并能够将事件绑定到视图的功能。

4

1 回答 1

3

我不会使用 knockoutjs html 绑定。

而是使用 durandals 组合绑定将新元素插入 dom。Durandal 也会为您处理绑定。

见这篇文章: http ://durandaljs.com/documentation/Using-Composition/

于 2013-06-27T23:32:51.130 回答