通过Jupyter笔记本_repr_javascript_方法

时间:2019-03-02 21:32:54

标签: javascript python jupyter-notebook jupyter

在Jupyter输出单元格内时,无法使用其ID检索新添加的html对象。我该怎么办?

编辑:我已经能够在Azure上托管的笔记本中复制相同的行为:

https://notebooks.azure.com/rickteachey/projects/sandbox/html/js_repr_id_access.ipynb

注意:要运行此笔记本,请单击右上角的Clone,然后在您自己的Azure项目/笔记本中运行它。

javacript首先使用Jupyter API添加新的html按钮(即element.html();在上下文中,element指Jupyter输出单元格<div>)。

然后代码尝试使用document.getElementById()访问按钮:

class C:
    def _repr_javascript_(self):
        return f'''
        element.html(`<button id="clearBtn">Clear</button>`)
        var x = document.getElementById("clearBtn")
        alert(x)
        '''

C()

预期的行为:警报应显示clearBtn html按钮对象的字符串化版本。

实际行为:警报显示一个空对象,这意味着脚本无法捕获clearBtn-即使我在查看源代码时可以在DOM中看到它。

我可能未正确使用API​​。如果是这样,我应该怎么做?

另一个奇怪的问题:当我在nbviewer上查看同一笔记本时,警报按预期方式弹出clearBtn html对象。在我的本地计算机或Azure上,它不会以这种方式运行。我应该将其报告为错误吗?

https://nbviewer.jupyter.org/urls/dl.dropbox.com/s/dwfmnozfn42w0ck/access_by_id_SO_question.ipynb

1 个答案:

答案 0 :(得分:2)

更新后的答案,以下为原文

我现在已经对此进行了测试,并认为我可以解决以下问题。为什么。具体来说,当生成输出单元格并将其插入页面时,它会按以下顺序发生:

  1. 页面从服务器接收数据。
  2. 解析HTML,包括<script>元素。
  3. 执行脚本,似乎以某种我尚未见过的方式将element置于其本地范围内。 (这与nbviewer页面中发生的情况不同,在nbviewer页面中,已经呈现了输出,并且脚本使用var element = $('#ad74eb90-4105-4cc9-83e2-37fb7e953a9f');之类的东西来获取它,可以在源代码中看到它。)
  4. 然后将HTML内容插入文档中。

这意味着在脚本运行时,element位于分离的DOM节点内。也可以使用以下方法进行检查:

alert(element[0].parentNode.parentNode)-> null

alert(element[0].parentNode.outerHTML)->

<div class="output_area">
    <div class="run_this_cell"></div>
    <div class="prompt output_prompt">
        <bdi>Out[28]:</bdi>
    </div>
    <div class="output_subarea output_javascript rendered_html">
        <button id="clearBtn">Clear</button>
    </div>
</div>

换句话说,渲染输出的所有操纵或遍历都需要通过element变量(例如$("#clearBtn", element)element.find("#clearBtn")甚至是element[0].querySelector("#clearBtn"))。它无法通过document,因为在脚本运行时该元素尚未成为文档的一部分。


原始答案:

这只是一个模糊的想法:在这种情况下,全局document可能实际上与element所在的文档不是同一文档吗?编辑器中可能会出现一些iframe内容,这可能解释了为什么它在被nbviewer渲染到单个页面之后而不是之前可以正常工作。 (即使iframe中的元素也不是父文档的一部分,即使浏览器的DOM查看器将它们嵌套在一起也是如此。)

我建议使用element,您已经必须找到刚刚插入按钮中的按钮,而不是尝试从document中找到它。 (我不确定element是哪种对象,但是应该有一种方法可以获取它所引用的DOM节点,然后使用.querySelector("#clearBtn"),对吗?)

编辑:如果element.html()行是jQuery代码,则element是jQuery对象,而element.find("#clearBtn")[0]将找到包含的按钮。

(这也可以用element[0].querySelector("#clearBtn")完成。请注意,.find()的返回值本身就是一个jQuery对象,而在jQuery对象上取消引用[0]则返回(第一个)里面的DOM元素。)