如何从一个灰烬子组件范围内访问父组件的范围? [英] how to access parent component scope from a child components scope in ember?
问题描述
我很好奇,如果这甚至有可能在灰烬。这是一件容易的事情在角(plunkr做:<一href=\"http://plnkr.co/edit/O2e0ukyXdKMs4FcgKGmX?p=$p$pview\">http://plnkr.co/edit/O2e0ukyXdKMs4FcgKGmX?p=$p$pview ):
我们的目标是使一个易于使用的,通用的,可重复使用的手风琴的API API的消费者。
我想要的主叫方能够使用该API是这样的(就像角API):
{{#烬,手风琴listOfAccordionPaneObjects =模型}} {{#烬,手风琴标题}}
标题HTML模板{{accordionPaneObject.firstName}}
{{/烬-手风琴标题}} {{#烬手风琴体}}
这是手风琴身体{{accordionPaneObject.lastName}}
{{/烬-手风琴体}}{{/烬,手风琴}}
下面是我使用的角度写了一个工作的例子:
&LT;!DOCTYPE HTML&GT;
&LT; HTML NG-应用=角手风琴&GT;
&LT; HEAD&GT;
&LT;风格&GT;
.angular手风琴头{
背景颜色:#999;
颜色:#FFFFFF;
填充:10px的;
保证金:0;
行高:14px的;
-webkit-边框左上角的半径:5像素;
-webkit-边框右上角半径:5像素;
-moz-边界半径-左上:5像素;
-moz-边界半径-topright:5像素;
边框左上角的半径:5像素;
边框右上角半径:5像素;
光标:指针;
文字修饰:无;
FONT-FAMILY:Helvetica Neue字体,黑体,宋体,无衬线;
字体大小:14px的;
} .angular手风琴容器{
高度:100%;
宽度:100%;
} .angular手风琴窗格{
填充:2px的;
} .angularaccordionheaderselected {
背景色:#bbb;
颜色:#333;
字体重量:大胆的;
} .angular-手风琴头:悬停{
文字修饰:强调重要的;!
} .angularaccordionheaderselected:悬停{
文字修饰:强调重要的;!
} .angular手风琴窗格内容{
填充:5像素;
溢出-Y:汽车;
左边框:1px的固体#bbb;
右边框:1px的固体#bbb;
下边框:1px的固体#bbb;
-webkit-边框左下角半径:5像素;
-webkit-边框右下半径:5像素;
-moz-边界半径-BOTTOMLEFT:5像素;
-moz-边界半径-bottomright:5像素;
边框左下角半径:5像素;
边框右下角半径:5像素;
} .angulardisabledpane {
不透明度:0.2;
}
&LT; /风格&GT;
&LT; /头&GT;
&LT;车身风格=保证金:0;&GT;
&LT; DIV的风格=高度:90%;宽度:100%;保证金:0; NG-控制器=outerController&GT; &LT;角手风琴列表的的手风琴窗格对象=outerControllerData&GT;
&LT;&窗格GT;
&LT;窗格中头&GT;头{{accordionPaneObject}}&LT; /窗格中头&GT;
&LT;窗格中的内容&gt;内容{{accordionPaneObject}}&LT; /窗格中的内容&GT;
&LT; /窗格&GT;
&LT; /角手风琴&GT;&LT; / DIV&GT; &所述; SCRIPT SRC =https://ajax.googleapis.com/ajax/libs/angularjs/1.2.1/angular.js&GT;&下; /脚本&GT;
&LT;脚本&GT;
angular.module('角手风琴,[])
.directive('angularAccordion',函数(){
VAR模板=''; 返回{
限制:'E',
transclude:真实,
更换:真实,
模板:'&LT; DIV&GT;' +
'&LT; DIV NG-transclude类=角手风琴容器NG重复=accordionPaneObject在listOfAccordionPaneObjects&GT;&LT; / DIV&GT;' +
'&LT; / DIV&GT;,
控制器:['$范围',函数($范围){
变种窗格= []; this.addPane =功能(窗格){
panes.push(面板);
};
}],
范围: {
listOfAccordionPaneObjects:'='
}
};
})
.directive('面板',函数(){
返回{
限制:'E',
transclude:真实,
更换:真实,
模板:'&LT; DIV NG-transclude类=角手风琴窗格&GT;&LT; / DIV&GT;'
};
})
.directive('paneHeader',函数(){
返回{
限制:'E',
要求:'^ angularAccordion',
transclude:真实,
更换:真实,
链接:功能(范围,iElement,iAttrs,控制器){
controller.addPane(范围); scope.toggle =功能(){
!scope.expanded = scope.expanded;
};
},
模板:'&LT; DIV NG-transclude类=角手风琴头NG点击=切换()&GT;&LT; / DIV&GT;'
};
})
.directive('paneContent',函数(){
返回{
限制:EA,
要求:'^ paneHeader',
transclude:真实,
更换:真实,
模板:'&LT; DIV NG-transclude类=角手风琴窗格内容NG秀=扩大&GT;&LT; / DIV&GT;'
};
})
.controller('outerController',['$范围',函数($范围){
$ scope.outerControllerData = [1,2,3];
}]);
&LT; / SCRIPT&GT;
&LT; /身体GT;
&LT; / HTML&GT;
在此处,我坚持做同样与Ember:
index.html的
&LT;!DOCTYPE HTML&GT;
&LT; HTML和GT;
&LT;身体GT;
&LT;脚本的src =// cdnjs.cloudflare.com/ajax/libs/require.js/2.1.9/require.js数据主要=main.js&GT;&LT; / SCRIPT&GT;
&LT; /身体GT;
&LT; / HTML&GT;
main.js
require.config({
路径:{
烬:bower_components /烬/烬,
'把手':'bower_components /车把/把手',
'jQuery的':'bower_components / jQuery的/ jQuery的,
文:bower_components / requirejs文/文
},
垫片:{
烬:{
DEPS:['jquery的','把手'],
出口:余烬
}
}
});定义(功能(需要){
VAR灰烬=要求(余烬),
EmberAccordionComponent =要求('SRC / EmberAccordionComponent'),
EmberAccordionTemplate =要求('的文字!模板/烬-accordion.hbs'),
EmberAccordionHeaderTemplate =要求('的文字!模板/烬-手风琴header.hbs'),
EmberAccordionBodyTemplate =要求('的文字!模板/烬-手风琴body.hbs'),
ApplicationTemplate =要求('的文字!模板/ application.hbs'),
IndexTemplate =要求('文本模板/ index.hbs!'); VAR应用= Ember.Application.create({
LOG_STACKTRACE_ON_DE preCATION:真实,
LOG_BINDINGS:真实,
LOG_TRANSITIONS:真实,
LOG_TRANSITIONS_INTERNAL:真实,
LOG_VIEW_LOOKUPS:真实,
LOG_ACTIVE_GENERATION:真
}); Ember.TEMPLATES = {};
Ember.TEMPLATES ['应用'] = Ember.Handlebars.compile(ApplicationTemplate);
Ember.TEMPLATES ['索引'] = Ember.Handlebars.compile(IndexTemplate);
Ember.TEMPLATES ['组件/烬-手风琴'] = Ember.Handlebars.compile(EmberAccordionTemplate);
Ember.TEMPLATES ['组件/烬-手风琴头'] = Ember.Handlebars.compile(EmberAccordionHeaderTemplate);
Ember.TEMPLATES ['组件/烬-手风琴体'] = Ember.Handlebars.compile(EmberAccordionBodyTemplate); App.EmberAccordionComponent = EmberAccordionComponent; App.IndexRoute = Ember.Route.extend({
型号:功能(){
返回[
{
名称:'鲍勃'
},
{
名称:'吉尔'
}]
}
})
});
EmberAccordionComponent.js
定义(功能(需要){
需要('烬'); 变种EmberAccordionComponent = Ember.Component.extend({}); 返回EmberAccordionComponent;
});
application.hbs
{{口}}
烬-手风琴header.hbs
&LT; DIV的风格=颜色:蓝色;&GT;
{{产量}}
&LT; / DIV&GT;
烬-手风琴body.hbs
&LT; DIV的风格=颜色:绿色;&GT;
{{产量}}
&LT; / DIV&GT;
index.hbs
{{#烬,手风琴listOfAccordionPaneObjects =模型}}
{{#烬手风琴头}}
{{登录this.constructor}}
{{登录此}}
头{{accordionPaneObject.name}}
{{/烬-手风琴头}}
{{#烬手风琴体}}
身体{{accordionPaneObject.name}}
{{/烬-手风琴体}}
{{/烬,手风琴}}
烬-accordion.hbs
{{#每个accordionPaneObject在listOfAccordionPaneObjects}}
{{产量}}
{{/每}}
-
这是棘手的调试。所以在投入:
{{登录this.constructor}}
和
{{记录此}}
到
{{#烬手风琴头}}
输出如下:
- Class.model =未定义(为什么?)
- Ember.ArrayController
我试过重写Ember.Component的私人_yield方法这篇文章(<一所建议href=\"http://www.thesoftwaresimpleton.com/blog/2013/11/21/component-block/\">http://www.thesoftwaresimpleton.com/blog/2013/11/21/component-block/ ):
VAR EmberAccordionHeaderComponent = Ember.Component.extend({
_yield:功能(背景下,期权){
VAR GET = Ember.get,
鉴于= options.data.view,
parentView = this._parentView,
模板=得到(这一点,'模板'); 如果(模板){
Ember.assert(A组分必须以得到具有父视图,parentView);
view.appendChild(Ember.View,{
isVirtual:真实,
标签名:'',
_contextView:parentView,
模板:模板,
背景:获得(查看,语境),//默认为得到(parentView,语境),
控制器:得到(查看,控制器),//默认为得到(parentView,语境),
templateData:{关键字:parentView.cloneKeywords()}
});
}
}
});
但我这样做的时候我还没有在我的子组件范围访问accordionPaneObject,我的{{登录this.constructor}}现在指向:.EmberAccordionHeaderComponent
因此,它看起来像我要去哪里,我只需要走一个多水平了。
当我尝试使用此code在EmberAccordionHeaderComponent.js:
VAR EmberAccordionHeaderComponent = Ember.Component.extend({
_yield:功能(背景下,期权){
VAR GET = Ember.get,
鉴于= options.data.view,
parentView = this._parentView,
grandParentView = this._parentView._parentView,
模板=得到(这一点,'模板'); 如果(模板){
Ember.assert(A组分必须以得到具有父视图,parentView);
view.appendChild(Ember.View,{
isVirtual:真实,
标签名:'',
_contextView:parentView,
模板:模板,
背景:得到(grandParentView,语境),//默认为得到(parentView,语境),
控制器:得到(grandParentView,控制器),//默认为得到(parentView,语境),
templateData:{关键字:parentView.cloneKeywords()}
});
}
}
});
我还是不访问accordionPaneObject,但是现在我看到{{登录this.constructor}}输出.EmberAccordionComponent。所以会出现,我在正确的范围,但数据仍然未绑定。
有趣的是,如果我使用任何在我重写_yield重新分配情况和控制器的这些变化,我可以访问我用我在控制台后的数据:
this._parentView._context.content
我更新了code的一些意见,请给看看的 http://emberjs.jsbin.com/ivOyiZa/1/edit 。
的JavaScript
应用= Ember.Application.create();App.IndexRoute = Ember.Route.extend({
型号:功能(){
返回[
{头:富脑袋,身体:富体},
{头:栏头,身体棒体},
{头道:你的头,身体:哟身体}
];
}
});App.EmberAccordionComponent = Ember.Component.extend({
//每个手风琴头/体项目,将有视图的实例。
//所以我们可以隔离展开状态的每个手风琴头/体
emberAccordionItemView:Ember.View.extend({
扩展:假的
}),
_yield:功能(背景下,期权){
VAR GET = Ember.get,
鉴于= options.data.view,
parentView = this._parentView,
模板=得到(这一点,'模板'); 如果(模板){
Ember.assert(A组分必须以得到具有父视图,parentView);
view.appendChild(Ember.View,{
isVirtual:真实,
标签名:'',
_contextView:parentView,
模板:模板,
背景:获得(查看,语境),//默认为得到(parentView,语境),
控制器:得到(查看,控制器),//默认为得到(parentView,语境),
templateData:{关键字:parentView.cloneKeywords()}
});
}
}
});App.EmberAccordionHeaderComponent = Ember.Component.extend({
类名:['烬手风琴头'],
点击:函数(){
//这里我们切换emberAccordionItemView.expanded财产
this.toggleProperty('parentView.expanded');
}
});
模板
&LT;脚本类型=文/ X-车把数据模板的名称=指数&GT;
{{#烬,手风琴listOfAccordionPaneObjects =模型}}
{{#烬手风琴头}}
{{头}}&LT;! - 在listOfAccordionPaneObjects传递的每个对象=模型可以访问这里 - &GT;
{{/烬-手风琴头}}
{{#烬手风琴体}}
{{身体}}&LT;! - 在listOfAccordionPaneObjects传递的每个对象=模型可以访问这里 - &GT;
{{/烬-手风琴体}}
{{/烬,手风琴}}
&LT; / SCRIPT&GT; &LT;脚本类型=文/ X-车把数据模板的名称=组件/烬-手风琴&GT;
{{#each listOfAccordionPaneObjects itemViewClass =view.emberAccordionItemView}}
&LT; DIV CLASS =烬-手风琴容器&GT;
&LT; DIV CLASS =烬-手风琴窗格&GT;
{{产量}}
&LT; / DIV&GT;
&LT; / DIV&GT;
{{/每}}
&LT; / SCRIPT&GT; &LT;脚本类型=文/ X-车把数据模板的名称=组件/烬-手风琴头&GT;
{{产量}}
&LT; / SCRIPT&GT; &LT;脚本类型=文/ X-车把数据模板的名称=组件/烬-手风琴体&GT;
&所述;! - 当EmberAccordionHeaderComponent.click被调用,膨胀属性的变化和该内容可以基于扩展真理是可见或不可见, - &GT;
{{#如果parentView.expanded}}
&LT; DIV CLASS =烬-手风琴窗格内容&GT;
{{产量}}
&LT; / DIV&GT;
{{/如果}}
&LT; / SCRIPT&GT;
的CSS
.ember手风琴头{
背景颜色:#999;
颜色:#FFFFFF;
填充:10px的;
保证金:0;
行高:14px的;
-webkit-边框左上角的半径:5像素;
-webkit-边框右上角半径:5像素;
-moz-边界半径-左上:5像素;
-moz-边界半径-topright:5像素;
边框左上角的半径:5像素;
边框右上角半径:5像素;
光标:指针;
文字修饰:无;
FONT-FAMILY:Helvetica Neue字体,黑体,宋体,无衬线;
字体大小:14px的;
}.ember手风琴容器{
高度:100%;
宽度:100%;
}.ember手风琴窗格{
填充:2px的;
}.emberaccordionheaderselected {
背景色:#bbb;
颜色:#333;
字体重量:大胆的;
}.ember-手风琴头:悬停{
文字修饰:强调重要的;!
}.emberaccordionheaderselected:悬停{
文字修饰:强调重要的;!
}.ember手风琴窗格内容{
填充:5像素;
溢出-Y:汽车;
左边框:1px的固体#bbb;
右边框:1px的固体#bbb;
下边框:1px的固体#bbb;
-webkit-边框左下角半径:5像素;
-webkit-边框右下半径:5像素;
-moz-边界半径-BOTTOMLEFT:5像素;
-moz-边界半径-bottomright:5像素;
边框左下角半径:5像素;
边框右下角半径:5像素;
}.emberdisabledpane {
不透明度:0.2;
}
I'm curious if this is even possible in ember. This is an easy thing to do in angular ( plunkr: http://plnkr.co/edit/O2e0ukyXdKMs4FcgKGmX?p=preview ):
The goal is to make an easy to use, generic, reusable accordion api for api consumers.
The api I want the caller to be able to use is this (just like the angular api):
{{#ember-accordion listOfAccordionPaneObjects=model}}
{{#ember-accordion-heading}}
heading template html {{accordionPaneObject.firstName}}
{{/ember-accordion-heading}}
{{#ember-accordion-body}}
this is the accordion body {{accordionPaneObject.lastName}}
{{/ember-accordion-body}}
{{/ember-accordion}}
Here is a working example I wrote using angular:
<!doctype html>
<html ng-app="angular-accordion">
<head>
<style>
.angular-accordion-header {
background-color: #999;
color: #ffffff;
padding: 10px;
margin: 0;
line-height: 14px;
-webkit-border-top-left-radius: 5px;
-webkit-border-top-right-radius: 5px;
-moz-border-radius-topleft: 5px;
-moz-border-radius-topright: 5px;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
cursor: pointer;
text-decoration: none;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
}
.angular-accordion-container {
height: 100%;
width: 100%;
}
.angular-accordion-pane {
padding: 2px;
}
.angularaccordionheaderselected {
background-color: #bbb;
color: #333;
font-weight: bold;
}
.angular-accordion-header:hover {
text-decoration: underline !important;
}
.angularaccordionheaderselected:hover {
text-decoration: underline !important;
}
.angular-accordion-pane-content {
padding: 5px;
overflow-y: auto;
border-left: 1px solid #bbb;
border-right: 1px solid #bbb;
border-bottom: 1px solid #bbb;
-webkit-border-bottom-left-radius: 5px;
-webkit-border-bottom-right-radius: 5px;
-moz-border-radius-bottomleft: 5px;
-moz-border-radius-bottomright: 5px;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
}
.angulardisabledpane {
opacity: .2;
}
</style>
</head>
<body style="margin: 0;">
<div style="height: 90%; width: 100%; margin: 0;" ng-controller="outerController">
<angular-accordion list-of-accordion-pane-objects="outerControllerData">
<pane>
<pane-header>Header {{accordionPaneObject}}</pane-header>
<pane-content>Content {{accordionPaneObject}}</pane-content>
</pane>
</angular-accordion>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.1/angular.js"></script>
<script>
angular.module('angular-accordion', [])
.directive('angularAccordion', function() {
var template = '';
return {
restrict: 'E',
transclude: true,
replace: true,
template: '<div>' +
'<div ng-transclude class="angular-accordion-container" ng-repeat="accordionPaneObject in listOfAccordionPaneObjects"></div>' +
'</div>',
controller: ['$scope', function($scope) {
var panes = [];
this.addPane = function(pane) {
panes.push(pane);
};
}],
scope: {
listOfAccordionPaneObjects: '='
}
};
})
.directive('pane', function() {
return {
restrict: 'E',
transclude: true,
replace: true,
template: '<div ng-transclude class="angular-accordion-pane"></div>'
};
})
.directive('paneHeader', function() {
return {
restrict: 'E',
require: '^angularAccordion',
transclude: true,
replace: true,
link: function(scope, iElement, iAttrs, controller) {
controller.addPane(scope);
scope.toggle = function() {
scope.expanded = !scope.expanded;
};
},
template: '<div ng-transclude class="angular-accordion-header" ng-click="toggle()"></div>'
};
})
.directive('paneContent', function() {
return {
restrict: 'EA',
require: '^paneHeader',
transclude: true,
replace: true,
template: '<div ng-transclude class="angular-accordion-pane-content" ng-show="expanded"></div>'
};
})
.controller('outerController', ['$scope', function($scope) {
$scope.outerControllerData = [1, 2, 3];
}]);
</script>
</body>
</html>
here's where I'm stuck doing the same with ember:
index.html
<!DOCTYPE html>
<html>
<body>
<script src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.1.9/require.js" data-main="main.js"></script>
</body>
</html>
main.js
require.config({
paths: {
'ember': 'bower_components/ember/ember',
'handlebars': 'bower_components/handlebars/handlebars',
'jquery': 'bower_components/jquery/jquery',
'text': 'bower_components/requirejs-text/text'
},
shim: {
ember: {
deps: ['jquery', 'handlebars'],
exports: 'Ember'
}
}
});
define(function(require) {
var Ember = require('ember'),
EmberAccordionComponent = require('src/EmberAccordionComponent'),
EmberAccordionTemplate = require('text!templates/ember-accordion.hbs'),
EmberAccordionHeaderTemplate = require('text!templates/ember-accordion-header.hbs'),
EmberAccordionBodyTemplate = require('text!templates/ember-accordion-body.hbs'),
ApplicationTemplate = require('text!templates/application.hbs'),
IndexTemplate = require('text!templates/index.hbs');
var App = Ember.Application.create({
LOG_STACKTRACE_ON_DEPRECATION : true,
LOG_BINDINGS : true,
LOG_TRANSITIONS : true,
LOG_TRANSITIONS_INTERNAL : true,
LOG_VIEW_LOOKUPS : true,
LOG_ACTIVE_GENERATION : true
});
Ember.TEMPLATES = {};
Ember.TEMPLATES['application'] = Ember.Handlebars.compile(ApplicationTemplate);
Ember.TEMPLATES['index'] = Ember.Handlebars.compile(IndexTemplate);
Ember.TEMPLATES['components/ember-accordion'] = Ember.Handlebars.compile(EmberAccordionTemplate);
Ember.TEMPLATES['components/ember-accordion-header'] = Ember.Handlebars.compile(EmberAccordionHeaderTemplate);
Ember.TEMPLATES['components/ember-accordion-body'] = Ember.Handlebars.compile(EmberAccordionBodyTemplate);
App.EmberAccordionComponent = EmberAccordionComponent;
App.IndexRoute = Ember.Route.extend({
model: function() {
return [
{
name: 'Bob'
},
{
name: 'Jill'
}]
}
})
});
EmberAccordionComponent.js
define(function(require) {
require('ember');
var EmberAccordionComponent = Ember.Component.extend({});
return EmberAccordionComponent;
});
application.hbs
{{outlet}}
ember-accordion-header.hbs
<div style="color: blue;">
{{yield}}
</div>
ember-accordion-body.hbs
<div style="color: green;">
{{yield}}
</div>
index.hbs
{{#ember-accordion listOfAccordionPaneObjects=model}}
{{#ember-accordion-header}}
{{log this.constructor}}
{{log this}}
Header {{accordionPaneObject.name}}
{{/ember-accordion-header}}
{{#ember-accordion-body}}
Body {{accordionPaneObject.name}}
{{/ember-accordion-body}}
{{/ember-accordion}}
ember-accordion.hbs
{{#each accordionPaneObject in listOfAccordionPaneObjects}}
{{yield}}
{{/each}}
--
This is tricky to debug. So putting in the:
{{log this.constructor}}
and the:
{{log this}}
into the:
{{#ember-accordion-header}}
outputs the following:
- Class.model = undefined (why?)
- Ember.ArrayController
I've tried overriding the private _yield method of Ember.Component as suggested by this article ( http://www.thesoftwaresimpleton.com/blog/2013/11/21/component-block/ ):
var EmberAccordionHeaderComponent = Ember.Component.extend({
_yield: function(context, options) {
var get = Ember.get,
view = options.data.view,
parentView = this._parentView,
template = get(this, 'template');
if (template) {
Ember.assert("A Component must have a parent view in order to yield.", parentView);
view.appendChild(Ember.View, {
isVirtual: true,
tagName: '',
_contextView: parentView,
template: template,
context: get(view, 'context'), // the default is get(parentView, 'context'),
controller: get(view, 'controller'), // the default is get(parentView, 'context'),
templateData: { keywords: parentView.cloneKeywords() }
});
}
}
});
but when I do this I still don't have access to accordionPaneObject in my child component scope, and my {{log this.constructor}} now points to: .EmberAccordionHeaderComponent
So it looks like I'm getting somewhere, I just need to go one more level up.
When I try that using this code in EmberAccordionHeaderComponent.js:
var EmberAccordionHeaderComponent = Ember.Component.extend({
_yield: function(context, options) {
var get = Ember.get,
view = options.data.view,
parentView = this._parentView,
grandParentView = this._parentView._parentView,
template = get(this, 'template');
if (template) {
Ember.assert("A Component must have a parent view in order to yield.", parentView);
view.appendChild(Ember.View, {
isVirtual: true,
tagName: '',
_contextView: parentView,
template: template,
context: get(grandParentView, 'context'), // the default is get(parentView, 'context'),
controller: get(grandParentView, 'controller'), // the default is get(parentView, 'context'),
templateData: { keywords: parentView.cloneKeywords() }
});
}
}
});
I still don't access to accordionPaneObject in, but now I see {{log this.constructor}} outputting .EmberAccordionComponent. So it appears I'm in the right scope, but the data still doesn't bind.
Interestingly enough, if I use any of these variations of reassigning context and controller in my overridden _yield, I can access the data I am after in the console using:
this._parentView._context.content
I updated your code with some comments please give a look http://emberjs.jsbin.com/ivOyiZa/1/edit.
Javascript
App = Ember.Application.create();
App.IndexRoute = Ember.Route.extend({
model: function() {
return [
{ head: "foo head", body: "foo body " },
{ head: "bar head", body: "bar body " },
{ head: "ya head", body: "yo body " }
];
}
});
App.EmberAccordionComponent = Ember.Component.extend({
// each accordion header/body item, will have a instance of that view.
// so we can isolate the expanded state for each accordion header/body
emberAccordionItemView: Ember.View.extend({
expanded: false
}),
_yield: function(context, options) {
var get = Ember.get,
view = options.data.view,
parentView = this._parentView,
template = get(this, 'template');
if (template) {
Ember.assert("A Component must have a parent view in order to yield.", parentView);
view.appendChild(Ember.View, {
isVirtual: true,
tagName: '',
_contextView: parentView,
template: template,
context: get(view, 'context'), // the default is get(parentView, 'context'),
controller: get(view, 'controller'), // the default is get(parentView, 'context'),
templateData: { keywords: parentView.cloneKeywords() }
});
}
}
});
App.EmberAccordionHeaderComponent = Ember.Component.extend({
classNames: ['ember-accordion-header'],
click: function() {
// here we toggle the emberAccordionItemView.expanded property
this.toggleProperty('parentView.expanded');
}
});
Templates
<script type="text/x-handlebars" data-template-name="index">
{{#ember-accordion listOfAccordionPaneObjects=model}}
{{#ember-accordion-header}}
{{head}} <!-- each object passed in listOfAccordionPaneObjects=model can be accessed here -->
{{/ember-accordion-header}}
{{#ember-accordion-body}}
{{body}} <!-- each object passed in listOfAccordionPaneObjects=model can be accessed here -->
{{/ember-accordion-body}}
{{/ember-accordion}}
</script>
<script type="text/x-handlebars" data-template-name="components/ember-accordion">
{{#each listOfAccordionPaneObjects itemViewClass="view.emberAccordionItemView"}}
<div class="ember-accordion-container">
<div class="ember-accordion-pane">
{{yield}}
</div>
</div>
{{/each}}
</script>
<script type="text/x-handlebars" data-template-name="components/ember-accordion-header">
{{yield}}
</script>
<script type="text/x-handlebars" data-template-name="components/ember-accordion-body">
<!-- when EmberAccordionHeaderComponent.click is called, the expanded property change and the content can be visible or not, based on expanded truth -->
{{#if parentView.expanded}}
<div class="ember-accordion-pane-content">
{{yield}}
</div>
{{/if}}
</script>
Css
.ember-accordion-header {
background-color: #999;
color: #ffffff;
padding: 10px;
margin: 0;
line-height: 14px;
-webkit-border-top-left-radius: 5px;
-webkit-border-top-right-radius: 5px;
-moz-border-radius-topleft: 5px;
-moz-border-radius-topright: 5px;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
cursor: pointer;
text-decoration: none;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
}
.ember-accordion-container {
height: 100%;
width: 100%;
}
.ember-accordion-pane {
padding: 2px;
}
.emberaccordionheaderselected {
background-color: #bbb;
color: #333;
font-weight: bold;
}
.ember-accordion-header:hover {
text-decoration: underline !important;
}
.emberaccordionheaderselected:hover {
text-decoration: underline !important;
}
.ember-accordion-pane-content {
padding: 5px;
overflow-y: auto;
border-left: 1px solid #bbb;
border-right: 1px solid #bbb;
border-bottom: 1px solid #bbb;
-webkit-border-bottom-left-radius: 5px;
-webkit-border-bottom-right-radius: 5px;
-moz-border-radius-bottomleft: 5px;
-moz-border-radius-bottomright: 5px;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
}
.emberdisabledpane {
opacity: .2;
}
这篇关于如何从一个灰烬子组件范围内访问父组件的范围?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!