在父模板外部渲染ember组件 [英] Rendering ember component outside parent template

查看:213
本文介绍了在父模板外部渲染ember组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

想象以下情况。我有一个侧边栏绝对定位,然后一些更多的东西定位绝对在侧边栏。在侧边栏中有一个按钮,显示一个菜单,模板如下:

 < button& / button> 
{{#if shouldDisplayMenu}}
{{view App.MyMenu}}
{{/ if}}

我喜欢这个解决方案,想保留的是模板中的菜单定义在按钮旁边,使得可维护性更好。



问题是,我想要相对于视口定位菜单,即渲染到document.body,并使用位置绝对定位。这样,它将渲染到边栏,并导致一个滚动条是可见的,因为我已经通过其中一个父元素的相对位置重置定位上下文。



有任何方式我可以保持{{view App.MyMenu}}现在,但它呈现到身体(可能使用插座或一些其他机制)?这种情况下推荐的模式是什么?

解决方案

有很多方法可以在 ember 和相关上下文。我提出了四种方法(我认为第一种更有可能是你要找的):



1。如果视图需要放置在句柄模板之外的某处,则可以使用jQuery将呈现的内容放置在任何需要的地方。



>(因为替换视图元素发生在 didInsertElement 之后,可能还需要添加样式以不显示元素 display:none ,并在重新定位后显示)



示例
http://emberjs.jsbin.com/gotabore/1/edit



2。如果该地点位于另一个模板中的某处,请使用 {{render}} 助手来呈现视图。虽然我不确定上下文的要求,这个帮手是相当灵活( http://emberjs.com/guides/templates/rendering-with-helpers/#toc_the-code-render-code-helper )。



示例
http://emberjs.jsbin.com/xibayava/1/edit



3。使用 {{outlet}} 基于在访问的路由中指定的视图。 ( http://emberjs.com/guides/routing/rendering-a-template/



示例
http: //emberjs.jsbin.com/tiyuqenu/1/edit



4。使用 ContainerView


http://emberjs.jsbin.com/yoyujeqi/1/edit



< hr>

对于等于或大于1.8.x的版本,方法4的更新 ,以避免 http://emberjs.com/guides/deprecations/#toc_global-lookup-of-views ,可以指定与 ContainerView 相关联的属性,如以下示例所示:



http://emberjs.jsbin.com/difayakeki/1/edit?html,js,output p>




相关代码



方法1

pre> < script type =text / x-handlebars>
< h2>欢迎使用Ember.js< / h2>

{{outlet}}
< / script>

< script type =text / x-handlebarsdata-template-name =index>
这是索引< br />
{{view App.TestView}}
< / script>
< script type =text / x-handlebarsdata-template-name =test>
这是测试视图< br />
< b> {{myProp}}< / b>
< / script>

< div id =a-divstyle =background-color:lightgray>
这是一个div的地方,< br />
< / div>

js

  App = Ember.Application.create(); 

App.Router.map(function(){
//将你的路由放在这里
});

App.IndexController = Ember.Controller.extend({
myProp:index controller prop
});

App.IndexView = Ember.View.extend({
placeTestViewSomewhere:function(){

var theTestView = this。$(。my-test-视图)。detach();
$(#a-div)append(theTestView);

} .on(didInsertElement)
}

App.TestView = Ember.View.extend({
templateName:test,
classNames:[my-test-view]
} ;

接近2



hbs

 < script type =text / x-handlebars> 
< h2>欢迎使用Ember.js< / h2>

{{outlet}}
< / script>

< script type =text / x-handlebarsdata-template-name =index>
这是索引< br />

< div style =background-color:lightgray>
这是一个使用render helper的索引模板中的div,< br />
{{rendertest}}
< / div>
< / script>
< script type =text / x-handlebarsdata-template-name =test>
这是测试视图< br />
< b> {{myProp}}< / b>
< / script>

js

  App.IndexView = Ember.View.extend({
placeTestViewSomewhere:function(){

// var theTestView = this。$( .my-test-view)。detach();
// $(#a-div)。append(theTestView);

} .on(didInsertElement)
});

App.TestController = Ember.Controller.extend({
myProp:test controller prop
});

App.TestView = Ember.View.extend({
templateName:test
});

接近3



hbs

 < script type =text / x-handlebars> 
< h2>欢迎使用Ember.js< / h2>

{{outlet}}
< div style =background-color:lightgray>
这是一个应用程序模板中的div,具有outlet帮助器,< br />
{{outlettest-outlet}}
< / div>
< / script>

< script type =text / x-handlebarsdata-template-name =index>
这是索引< br />

< / script>
< script type =text / x-handlebarsdata-template-name =test>
这是测试视图< br />
< b> {{myProp}}< / b>
< / script>

js

  App.IndexRoute = Ember.Route.extend({
renderTemplate:function(){
this.render(index);
.render('test',{//将
转换为:'application'的模板,//渲染到的模板
outlet:'test-outlet'那个模板
});
}
});

App.IndexView = Ember.View.extend({
placeTestViewSomewhere:function(){

// var theTestView = this。$(。my-测试视图)。detach();
// $(#a-div)。append(theTestView);

} .on(didInsertElement)
});

App.TestController = Ember.Controller.extend({
myProp:test controller prop
});

App.TestView = Ember.View.extend({
templateName:test
});

方法4



hbs

 < script type =text / x-handlebars> 
< h2>欢迎使用Ember.js< / h2>

{{outlet}}
< div style =background-color:lightgray>
这是一个应用程序模板中的div,包含视图助手和视图容器,< br />
{{view Ember.ContainerView viewName =my-menu-container}}
< / div>

< / div>
< / script>

< script type =text / x-handlebarsdata-template-name =index>
这是索引< br />
< / script>
< script type =text / x-handlebarsdata-template-name =test>
这是测试视图< br />
< b> {{myProp}}< / b>
< / script>

js

  App.IndexController = Ember.Controller.extend({
myProp:index controller prop
});

App.IndexView = Ember.View.extend({
placeTestViewSomewhere:function(){

var theTestView = App.TestView.create({});
theTestView.set(context,this.get(context));
this.get(parentView.my-menu-container)。pushObject(theTestView);

} .on(didInsertElement)
});


App.TestView = Ember.View.extend({
templateName:test
});






strong>



js

  .ApplicationView = Em.View.extend({
containerView:Em.ContainerView
});



hbs pre> {{view view.containerView viewName =my-menu-container}}


Imagine the following situation. I have a sidebar positioned absolutely and then some more stuff positioned absolutely within that sidebar. In that sidebar I have a button, which shows a menu, the template looks like this:

<button>Click me</button>
{{#if shouldDisplayMenu}}
    {{view App.MyMenu}}
{{/if}}

What I like about this solution and want to keep is that the menu in the template is defined right next to the button, making for nice maintainability.

The problem is that I want the menu to be positioned relative to the viewport, i.e. rendered to document.body and positioned using position absolute. This way it will render into the sidebar and cause a scrollbar to be visible because I have already reset positioning context via position relative in one of the parent elements.

Is there any way I can keep {{view App.MyMenu}} where it is now, but have it render to body (perhaps using outlets or some other mechanism)? What is the recommended pattern for a situation like this?

解决方案

There are plenty of ways to render views in ember with related context. I present four approaches (i think the first is more likely what you are looking for) :

1. If the view is required to be placed somewhere out of a handlebars template, it is possible to use jQuery to place the rendered content wherever it is required to be.

(since the replacement of the view element is happening after didInsertElement it is probably required to also add styles to not show the element eg display:none , and show it after it has been repositioned)

Example http://emberjs.jsbin.com/gotabore/1/edit

2. Use {{render}} helper to render the view in place if that place is somewhere in another template. Although i'm not certain about the context requirements, this helper is pretty flexible (http://emberjs.com/guides/templates/rendering-with-helpers/#toc_the-code-render-code-helper).

Example http://emberjs.jsbin.com/xibayava/1/edit

3. Use {{outlet}} helper to render the view based on what is specified within the visited route. (http://emberjs.com/guides/routing/rendering-a-template/)

Example http://emberjs.jsbin.com/tiyuqenu/1/edit

4. Use a ContainerView to push a view programmatically anywhere it is required to be.

Example http://emberjs.jsbin.com/yoyujeqi/1/edit


UPDATE for approach 4: for versions equal or greater than 1.8.x , to avoid the error mentioned in http://emberjs.com/guides/deprecations/#toc_global-lookup-of-views , it is possible to specify a property associated to the ContainerView as shown in the following example

http://emberjs.jsbin.com/difayakeki/1/edit?html,js,output


related code

approach 1

hbs

<script type="text/x-handlebars">
    <h2> Welcome to Ember.js</h2>

    {{outlet}}
  </script>

  <script type="text/x-handlebars" data-template-name="index">
    This is index<br/>
    {{view App.TestView}}
  </script>
  <script type="text/x-handlebars" data-template-name="test">
    This is the test view<br/>
    <b>{{myProp}}</b>
  </script>

  <div id="a-div" style="background-color:lightgray">
    This is a div somewhere,<br/>
  </div>

js

App = Ember.Application.create();

App.Router.map(function() {
  // put your routes here
});

App.IndexController = Ember.Controller.extend({
  myProp:"index controller prop"
});

App.IndexView = Ember.View.extend({
  placeTestViewSomewhere:function(){

    var theTestView = this.$(".my-test-view").detach();
    $("#a-div").append(theTestView);

  }.on("didInsertElement")
});

App.TestView = Ember.View.extend({
  templateName:"test",
  classNames:["my-test-view"]
});

approach 2

hbs

<script type="text/x-handlebars">
    <h2> Welcome to Ember.js</h2>

    {{outlet}}
  </script>

  <script type="text/x-handlebars" data-template-name="index">
    This is index<br/>

    <div style="background-color:lightgray">
    This is a div in index template with render helper,<br/>
    {{render "test"}}
  </div>
  </script>
  <script type="text/x-handlebars" data-template-name="test">
    This is the test view<br/>
    <b>{{myProp}}</b>
  </script>

js

App.IndexView = Ember.View.extend({
  placeTestViewSomewhere:function(){

//     var theTestView = this.$(".my-test-view").detach();
//     $("#a-div").append(theTestView);

  }.on("didInsertElement")
});

App.TestController = Ember.Controller.extend({
  myProp:"test controller prop"
});

App.TestView = Ember.View.extend({
  templateName:"test"
});

approach 3

hbs

<script type="text/x-handlebars">
    <h2> Welcome to Ember.js</h2>

    {{outlet}}
    <div style="background-color:lightgray">
    This is a div in application template with outlet helper,<br/>
    {{outlet "test-outlet"}}
  </div>
  </script>

  <script type="text/x-handlebars" data-template-name="index">
    This is index<br/>

  </script>
  <script type="text/x-handlebars" data-template-name="test">
    This is the test view<br/>
    <b>{{myProp}}</b>
  </script>

js

App.IndexRoute = Ember.Route.extend({
  renderTemplate: function() {
    this.render("index");
    this.render('test', {   // the template to render
      into: 'application',                // the template to render into
      outlet: 'test-outlet'             // the name of the outlet in that template
    });
  }
});

App.IndexView = Ember.View.extend({
  placeTestViewSomewhere:function(){

//     var theTestView = this.$(".my-test-view").detach();
//     $("#a-div").append(theTestView);

  }.on("didInsertElement")
});

App.TestController = Ember.Controller.extend({
  myProp:"test controller prop"
});

App.TestView = Ember.View.extend({
  templateName:"test"
});

approach 4

hbs

<script type="text/x-handlebars">
    <h2> Welcome to Ember.js</h2>

    {{outlet}}
    <div style="background-color:lightgray">
    This is a div in application template with view helper and a view container,<br/>
    {{view Ember.ContainerView viewName="my-menu-container"}}
  </div>

  </div>
  </script>

  <script type="text/x-handlebars" data-template-name="index">
    This is index<br/>
  </script>
  <script type="text/x-handlebars" data-template-name="test">
    This is the test view<br/>
    <b>{{myProp}}</b>
  </script>

js

App.IndexController = Ember.Controller.extend({
  myProp:"index controller prop"
});

App.IndexView = Ember.View.extend({
  placeTestViewSomewhere:function(){

    var theTestView = App.TestView.create({});
    theTestView.set("context",this.get("context"));
    this.get("parentView.my-menu-container").pushObject(theTestView);

  }.on("didInsertElement")
});


App.TestView = Ember.View.extend({
  templateName:"test"
});


UPDATE for approach 4:

js

App.ApplicationView = Em.View.extend({
  containerView:Em.ContainerView
});

hbs

{{view view.containerView viewName="my-menu-container"}}

这篇关于在父模板外部渲染ember组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆