In AngularJS (1.x), how can we create a reusable widget (component) that has insertion points (slots) for other widgets (components)?
Imagine we have a component/directive called "verticalsplitter". It's purpose is to divide the screen area into a "top" and "bottom" area (perhaps allowing user resizing, collapsing, etc).
Now imagine we have a bunch of other rich components e.g. a richtextview, a treeview, a videoplayer and a gridview.
One page/view 1 I want a verticalsplitter with a richtextview on top and treeview on bottom. On page/view 2 I want a verticalsplitter with a videoplayer on top and a gridview on bottom.
Page 1
<html>
<body>
<verticalsplitter>
<top ng-initialSize="30%">
<richtextview />
</top>
<bottom ng-initialSize="70%">
<treeview />
</bottom>
</verticalsplitter>
</body>
</html>
Page 2
<html>
<body>
<verticalsplitter ng-locked="true">
<top>
<videoplayer />
</top>
<bottom>
<gridview />
</bottom>
</verticalsplitter>
</body>
</html>
How can I achieve this? If it's not possible with components (and I need to use directives for transclude) then that's OK.
Components can transclude. It is clearly stated so in the AngularJS Developers Guide for Components:
app.component("verticlesplitter", {
transclude: {
'topPart': 'top',
'bottomPart': 'bottom'
},
template: `
<div style="border: 1px solid black;">
<div class="top" ng-transclude="topPart"></div>
<div>Something in the middle</div>
<div class="bottom" ng-transclude="bottomPart"></div>
</div>
`
});
For more information, see
AngularJS Developers Guide for Components
AngularJS ng-transclude Directive API Reference (Multi-slot Transclusion)
Related
I am trying to render a Chart JS canvas via a slot;
chartWrapper.html
<template>
<div class="chart-wrapper">
<slot name="chart"></slot>
</div>
</template>
chartWrapperContainer.html
<c-chart-wrapper>
<canvas slot="chart" class="donut" lwc:dom="manual"></canvas>
</c-chart-wrapper>
The chart does not render and the canvas in the rendered Markup shows 0 width and height. Rendering without the slot works well; I need to wrap it into a slot for structural reasons.
What could be wrong with this?
This was sorted out by wrapping the canvas in a div; made some logical sense to me not to push a plain 'photo' into a slot whose internals it's unaware of.
<!-- chartWrapper.html -->
<template>
<div class="chart-wrapper">
<slot name="chart"></slot>
</div>
</template>
<!-- chartWrapperContainer.html -->
<c-chart-wrapper>
<div slot="chart">
<canvas class="donut" lwc:dom="manual"></canvas>
</div>
</c-chart-wrapper>
Alternately, you could set a CSS property that defines the Custom Element as a block, or inline-block through the :host pseudo-class. (By default a custom element has its display value set to inline.)
Then you can set its height and width or let the default ones:
<!-- chartWrapper.html -->
<template>
<style>
:host {
display: inline-block ;
width: 50% ;
height: 200px ;
}
</style>
<slot></slot>
</template>
I have components created with ng-repeat and I want them to be flex children:
<div style="display:flex; flex-wrap: wrap">
<div ng-repeat="item in data" style="flex-basis: 30%">
<my-component item="item"></my-component>
</div>
<div>
Where my component's template is:
<div class="c">
...
</div>
It is kind of working, but the my-component items are not all in the same height as they would have been if they were simply divs.
I can workaround this by setting .c{height: 100%} but it messes up with the wrapping.
Can I acheive this behaviour with AngularJS 1.5 at all?
Attached codepen for repro: http://codepen.io/anon/pen/ENqvvO
Thanks!
The problem is that when using the component you have a new element wraping the div.c element, so that the flex behaviour doesn't bound the two elements of your css. Your example (from plunkr) without the component works because it doesn't have the my-component in between.
div.flex-container
my-component // <- this guy is breaking off the flex connection
div.c
In order to fix it you can style the tag my-component instead of .c so that the flex can be applied directly between div.flex-container and my-component.
Actually I recommend you to create a container component and an item component so that things are kept clear and solid.
For example:
<list>
<list-item>Item 1</list-item>
<list-item>Item 2</list-item>
<list-item>Item 3</list-item>
<list-item ng-repeat="item in items"> {{ item }} </list-item>
</list>
And also:
<gallery>
<gallery-item ng-repeat="photo in photos">
<photo img="photo "></photo>
</gallery-item>
</galery>
Beautiful, isn't it? :{D
I have a directive which uses three different templates:
http://jsfiddle.net/edwardtanguay/pLrkya7r/4
These templates each have a panel and I want them to include a header template which is the same for each of them, like this:
<script type="text/ng-template" id="itemMenuTemplateUndefined">
<div class = "panel panel-default" >
<div ng-include="'itemMenuTemplatePanelHeading'"></div>
<div class="panel-body">
<div>Age: {{item.age}}</div>
</div >
</div>
</script>
The included template looks like this:
<script type="text/ng-template" id="itemMenuTemplatePanelHeading">
<div class="panel-heading">{{item.firstName}} <b>{{item.lastName}}</b> (PROBLEM INCLUDED BUT NO COLOR)</div>
</script>
The problem is that although it includes the scope variable values and HTML, it doesn't seem to have the same HTML structure which causes e.g. the panel header color not to display.
How can I get this example to work so that it has the same HTML structure as without ng-include so that Bootstrap continues to work?
The problem is that the bootstrap css is very specific in targeting the panel heading as a direct child of the panel using selectors like .panel-warning>.panel-heading.
The extra <div> for the ng-include breaks this child relationship making it
<div class="panel">
<div ng-include>
<div class="panel-heading>
Some possible choices:
Add appropriate classes to the ng-include div
Copy the css rules and replace the > in selector with a space
Use your own directive instead of ng-include and within the options
set replace:true
I'm trying to build a directive which will display a kendo window with a kendo tab strip in its body content.
It's a component I need to be reusable since I use it a lot in my web app.
Here is the flat html representation that I want to turn into a directive
<div style="padding:20px;" kendo-window="test" id="test" k-title="hello" k-options="popupOptions">
<div kendo-tab-strip k-content-urls="[ null, null]">
<!-- tab list -->
<ul>
<li class="k-state-active">View</li>
<li>Edit</li>
</ul>
<div style="padding: 1em">
This is the view tab
</div>
<div style="padding: 1em">
This is the edit tab
</div>
</div>
</div>
1) First step is creating the directive that wraps the kendo popup and this si where I'm having an issue
So basically, my directive includes the kendo-window widget in its template and has transclude="true", since the content of the popup will different each time.
It seems "transclude" and "scope" cause some issues.
Please have a look : http://plnkr.co/edit/c7qoKlh75s8aS7fazYSo
I would like to create a sort of double dropdown. For example, initially the selection box is empty with a down arrow. If you click the arrow you get a dropdown with two entries: MA and NH. If you then click MA you get another dropdown with Boston and Worcester. If you click NH you get a dropdown Concord and Nashua.
As far as I know, this isn't connected with CakePHP. CakePHP is a server-side PHP framework, not client-side library. This can be done with JavaScript, I recommend using jQuery Library here.
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="dropdown">
Hover me
<div class="state">
MA
<div class="city">Boston</div>
<div class="city">Worcester</div>
</div>
<div class="state">
NH
<div class="city">Concord</div>
<div class="city">Nashua</div>
</div>
</div>
<style>
#dropdown{background-color: yellow;width:200px}
.state{background-color: orange;}
.city{background-color: lime;}
.city,.state{display:none}
</style>
<script>
$(document).ready(function(){
$("#dropdown").mouseenter(function(){
$(this).find(".state").show()
$(this).find(".city").hide()
}).mouseleave(function(){
$(this).find(".state").hide()
})
$(".state").mouseenter(function(){
$(".city").hide()
$(this).find(".city").show()
}).mouseleave(function(){
$(".city").hide()
})
})
</script>
This code is just for explanation. It is not optimized, but 100% working.
Never use inline styles and scripts.