I'd like to transclude multiple pieces into one directive. Here is my idea of how I'd set it up.
<div id="content" class="mainDirective">
<div class="sub">
<ul>
<li>Everyone</li>
<li>Development (3)</li>
<li>Marketing</li>
</ul>
</div>
<div class="subButtons">
<span class="csStIcon add" data-ng-click="addTeam()"></span>
<span class="csStIcon edit" data-ng-click="editTeam()"></span>
<span class="csStIcon delete" data-ng-click="deleteTeam()"></span>
</div>
<div class="main">
<table>
<thead>
<tr><td>Name</td><td>Last name</td><td>Department</td></tr>
</thead>
<tbody>
<tr><td>Lorem</td><td>Ipsum</td><td>Development</td></tr>
<tr><td>Lorem</td><td>Ipsum</td><td>Development</td></tr>
<tr><td>Lorem</td><td>Ipsum</td><td>Development</td></tr>
</tbody>
</table>
</div>
</div>
My directive template:
<div>
<div class="left">
<div data-ng-multi-transclude="sub"></div>
<div class="bottomOptions">
<span class="csStIcon collapse"></span>
<div data-ng-multi-transclude="subButtons"></div>
</div>
</div>
<div class="right">
<div data-ng-multi-transclude="main"></div>
</div>
</div>
And the final output:
<div>
<div class="left">
<div class="sub">
<ul>
<li>Everyone</li>
<li data-ng-click="loadDepartment()">Development (3)</li>
<li data-ng-click="loadDepartment()">Marketing</li>
</ul>
</div>
<div class="bottomOptions">
<span class="csStIcon collapse"></span>
<div class="subButtons">
<div class="subButtons">
<span class="csStIcon add" data-ng-click="addTeam()"></span>
<span class="csStIcon edit" data-ng-click="editTeam()"></span>
<span class="csStIcon delete" data-ng-click="deleteTeam()"></span>
</div>
</div>
</div>
</div>
<div class="right">
<div class="main">
<table>
<thead>
<tr><td>Name</td><td>Last name</td><td>Department</td></tr>
</thead>
<tbody>
<tr><td>Lorem</td><td>Ipsum</td><td>Development</td></tr>
<tr><td>Lorem</td><td>Ipsum</td><td>Development</td></tr>
<tr><td>Lorem</td><td>Ipsum</td><td>Development</td></tr>
</tbody>
</table>
</div>
</div>
</div>
Is this possible within angular?
I ended up needing this functionality as well, so I wrote ng-multi-transclude -- funnily enough, I hadn't seen this question at the time, just lucked into the same name.
Usage is almost exactly as your question sketches; the only difference is that you use the name attribute to pick the "hole" to fill instead of the class attribute.
This has been added in angular 1.5
http://angularjs.blogspot.ca/2016/02/angular-150-ennoblement-facilitation.html
I came up with this directive using transclude function:
app.directive('mainDirective', function($compile) {
var template = ['<div>',
' <div class="left">',
' <div data-ng-multi-transclude="sub"></div>',
' <div class="bottomOptions">',
' <span class="csStIcon collapse"></span>',
' <div data-ng-multi-transclude="subButtons"></div>',
' </div>',
' </div>',
' <div class="right">',
' <div data-ng-multi-transclude="main"></div>',
' </div>',
'</div>'].join('\n');
return {
restrict: 'C',
transclude: true,
template: template,
link: function(scope, element, attr, model, transclude) {
var places = element.find('[data-ng-multi-transclude]');
console.log(element);
places.each(function() {
var self = $(this);
var class_ = self.data('ng-multi-transclude');
transclude(scope.$new(), function(clone, scope) {
var item = clone.closest('.' + class_);
$compile(item)(scope).appendTo(self);
});
});
}
};
});
I've used compile so you can use angular inside your transcluded code.
If you use this:
self.replaceWith($compile(item)(scope));
you'll don't get those original wrappers divs with data-ng-multi-transclude attributes.
Also you need to have jQuery included (always before Angular, because otherwise you get jQLite instead).
I have used multiple 'transclusions' in the component I am writing. In practice, it's just nested directives but they get the job done: https://github.com/AlexCppns/ac-fancy-input
More specifically, have a look at the following file:
https://github.com/AlexCppns/ac-fancy-input/blob/master/src/ac-fancy-input/directives/fancy-input.js
Related
I am trying to find the parent of the span element with label First Name and go up the DOM until i get to the input element with class "mat-input-element"
I have attempted with the following xpath, but did not get the result i needed:
//div/div/span[contains(.,'First Name')]/parent::div[#class='add-users']/lib-text-input-v3/div/mat-form-field/div/div/div[1]/input
Any help would be appreciated. Thanks!
You can try with the below xpath.
//span[normalize-space(.)='First Name']/ancestor::div[#class='input-v3']//input[#class='mat-input-element']
Sample HTML: From jsfiddle
<html><head></head><body>
<div class="add-users">
<lib-text-input-v3 errortext="”Error" a="" valid="" first="" name”="">
<div class="input-v3">
<mat-form-field class="mat-form-field">
<div class="mat-form-field-wrapper">
<div class="mat-form-field-flex">
<div class="mat-form-field-infix">
<input class="mat-input-element" type="text">
<span class="mat-form-field-label-wrapper">
</span>
</div>
</div>
<div class="mat-form-field-underline>
<span class=" mat-form-field-ripple"="">
</div>
<div class="mat-form-field-subscript-wrapper">
<div class="mat-form-field-hint-wrapper">
<div class="mat-form-field-hint-spacer">
</div>
</div>
</div>
</div>. //closes mat-form-field-wrapper class
</mat-form-field>
<div class="input-v3__label"> // same level as input-v3 class
<div class="input-v3__label--text">
<span class="ng-tns-c11-01">First Name
</span>
</div>
</div>
</div> // closes input-v3 class
</lib-text-input-v3>
<lib-text-input-v3>…..
</lib-text-input-v3></div></body></html>
So I kept sketching out algorithms to see how this would work. Kept hitting my head on the keyboard because frankly, nothing seems to work. Basically the hardcoded HTML looks like this:
<div class="row">
<div class="column">
<a href="products.html#drinks"><div id="drinks">
<h2>Drinks</h2>
</div></a>
</div>
<div class="column">
<a href="products.html#preppedfood"><div id="preppedfood">
<h2>Prepped Food</h2>
</div></a>
</div>
<div class="column">
<a href="products.html#coffee"><div id="coffee">
<h2>Coffee Machines</h2>
</div></a>
</div>
<div class="column">
<a href="products.html#snacks"><div id="snacks">
<h2>Snacks</h2>
</div></a>
</div>
</div>
<div class="row">
<div class="column">
<a href="products.html#nuts"><div id="nuts">
<h2>Nuts of All Kinds</h2>
</div></a>
</div>...till the last div class="row" and it's column divs
So the HTML works fine, here's a screenshot:
This is how I want it to look!
But using VueJS so that I can "DRY out" my markup, I'm using the v-for directive like this in the Prods.vue component. Here's the template markup:
<div class="row" v-for="(data, index) in images" v-bind:key="data" v-if="data.ImageId%4 == 0">
<h1>{{index}}</h1>
<div
class="column"
v-for="data in images"
v-bind:key="data"
v-if="computedIndex(index) *4 >= index && index < (computedIndex(index)+1) / 4"
v-lazy-container="{ selector: 'data' }"
>
<a :href="'products/#'+data.Name">
<h4>{{data.H2}}</h4>
<img :src="'../../../static/products/'+data.Name+'.png'" :alt="data.Name+'.png'" />
</a>
</div>
</div>
And the script:
<script>
import Prods from '../../../other/jsons/products.json'
import VueLazyload from 'vue-lazyload'
export default {
data() {
return {images: Prods}
},
methods: {
computedIndex(index) {
return Math.trunc(index/4)
}
}
}
//v-for in row
//v-for in column
</script>
And this is what shows up instead:
enter image description here
Instead of juggling with indices, it seems more straightforward to me to compute the shape of your array to suit your DOM:
computed:
imageRows () {
return this.images.reduce((acc, n, i) => {
i % 4 ? acc[acc.length - 1].push(n) : acc.push([n])
return acc
}, [])
}
To be used something like this:
<table>
<tr v-for="(imageRow, i) in imageRows" :key="i">
<td v-for="image in imageRow" :key="image">
<foo/>
</td>
</tr>
</table>
(Your data seems tabular to me, so I'm showing this example as a <table>, but you can substitute that with <div>'s if you prefer, of course.)
I am trying to make a list of buttons appear, and once selected for the appropriate div underneath the button to be shown, I have used similar code before:
<li><button class="w3-button w3-grey w3-hover-dark-grey w3-round-xxlarge" ng-click="section = !section">Structure and function of the processor</button></li>
Which works fine so I am guessing it has something to do with $index
Do you have any idea how I could achieve this?
<div class="w3-panel" ng-show="section">
henlo content
</div>
<div ng-app="tApp" ng-controller="tController">
<ul class="w3-ul">
<div ng-repeat="x in items">
<li>
<button class="w3-button w3-grey w3-hover-dark-grey w3-round-xxlarge" ng-click="section{{$index}} = !section{{$index}}">{{x.name}}</button>
</li>
<div class="w3-panel" ng-show="section{{$index}}">
{{x.content}}
</div>
</div>
</ul>
</div>
<script>
var app=angular.module("tApp", []);
app.controller("tController", function($scope)
{
$scope.items=[{name:"first",content:"henlo first"},{name:"second", content:"henlo second"}];
});
</script>
you can initialise a property with ng-init and use that property to show/hide content
<div ng-repeat="x in items" ng-init="x.displayContent = false">
<li>
<button class="w3-button w3-grey w3-hover-dark-grey w3-round-xxlarge" ng-click="x.displayContent = !x.displayContent">{{x.name}}</button>
</li>
<div class="w3-panel" ng-show="x.displayContent">
{{x.content}}
</div>
</div>
I have a json inside a ng-init where I have some data and I want to grab these data and paint into a template and I compiled with my directive and I don't have idea what I'm doing wrong. I can not paint json data into the template
example:
<li ng-init="product= {"brand":"Nike", "price":"30€", "mainImage":"images/images.jpg"}>
<div class="content-product>
<div class="product">
<p>Nike </p>
<img src="image.jpg" alt="">
<p>30€ </p>
</div>
</div>
</li>
This li is inside a loop in ruby.
Template where I want to paint the data and compile this template when I click on a button that is inside the li:
<script type="text/ng-template" id="quickpreview.html">
<div class="content-preview">
<div class="content-preview-inner">
<span class="full-preview"></span>
<span class="close-preview"></span>
<div class="block block-left left">
<div class="content-tabs">
<dl class="tabs vertical" data-tab>
<dd class="active">Tab 1
</dd>
<dd>Tab 2
</dd>
<dd>Tab 3
</dd>
<dd>Tab 4
</dd>
<dd>Tab 5
</dd>
</dl>
<div class="tabs-content vertical">
<div class="content active" id="panel1">
<div class="content-img">
<div class="main-img">
<img ng-src="{{product.mainImage}}" alt="">
</div>
<div class="thumbnails">
<a class="th" role="button" aria-label="Thumbnail" href="">
<img aria-hidden=true src="" />
</a>
</div>
</div>
</div>
<div class="content" id="panel2">
<p>This is the second panel of the basic tab example. This is the second panel of the basic tab example.</p>
</div>
<div class="content" id="panel3">
<p>This is the third panel of the basic tab example. This is the third panel of the basic tab example.</p>
</div>
<div class="content" id="panel4">
<p>This is the fourth panel of the basic tab example. This is the fourth panel of the basic tab example.</p>
</div>
<div class="content" id="panel5">
<p>This is the fifth panel of the basic tab example. This is the fourth panel of the basic tab example.</p>
</div>
</div>
</div>
</div>
<div class="block block-right right">
<div class="content-details">
<div class="details">
<h3 class="title-product">{{product.brand}}</h3>
<h2 class="short-desc">{{product.shortname}}</h2>
<div class="block-price">
</div>
</div>
</div>
</div>
</div>
</div>
my directive and controller:
(function() {
'use strict';
var app = angular.module('quickPreview');
app.controller('globalCtrl', function ($scope) {
// var e = angular.element($("[ng-init]"));
// console.log(e);
// $scope.product = e.attr('ng-init');
// console.log($scope.product);
$scope.product = [];
var logSomeStuff = function(){
console.log($scope.product);
}
$scope.$evalAsync(logSomeStuff);
});
}(window, window.angular));
(function (){
"use strict";
var app = angular.module('quickPreview');
app.directive('previewProduct', function ($compile,$templateCache) {
return {
restrict: 'A',
replace: false,
transclude: false,
scope: {
attrData: '=dataOverview'
},
link: function(scope, element, attrs) {
element.bind('click', '.sd-click-preview', function (){
var preview = angular.element($templateCache.get('quickpreview.html'));
var cpreview = $compile(preview);
element.append(preview);
cpreview(scope);
console.log(cpreview(scope))
if (scope.attrData) {
console.log(this, '=> this');
}
});
}
};
});
}(window, window.angular));
You don't need quotes in ng-init statement. You are ending the statement prematurely.
<li ng-init="product= {brand:'Nike', price:'30€', mainImage:'images/images.jpg'}">
<div class="content-product">
<div class=" product ">
<p>{{product.brand}}</p>
<img ng-src="{{product.mainImage}} " alt=" ">
<p>{{product.price}}</p>
</div>
</div>
</li>
Here's a working example:http://plnkr.co/edit/XRyYefxncZuqE5GeA3XG?p=preview
I am using x-editable js. My x-editable popover is not shown completely.
I think problem in z-index, I tried it on hyperlink but no luck.
<script type="text/javascript">
$(function () {
$('.extraSectionTitle').editable({
success: function (response, newValue) {
if (response.status == 'error') {
return response.msg;
}
}
});
$('.extraSectionDescription').editable({
success: function (response, newValue) {
if (response.status == 'error') {
return response.msg;
}
}
});
});
</script>
<div class="row-fluid">
<div class="span7">
<div class="accordion-body collapse in">
<div class="row-fluid" id="myDiv">
<div class="box box-color box-bordered">
<div class="box-title">
<h3><i class="icon-th-list"></i> Hi</h3>
</div>
<div class="box-content nopadding">
<table class="table table-hover table-nomargin table-bordered">
<thead>
<tr>
<th>Title</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<a class="editable editable-click extraSectionTitle" data-original-title="Edit Title" data-pk="1" data-type="text" href="#" data-url="#" data-placement="right" title="Edit Title">ASD ASD ASD ASD ASD </a>
</td>
<td>
<a class="editable editable-click extraSectionDescription" data-original-title="Edit Description" data-pk="${extra?.id}" data-type="text" href="#" data-url="#" data-placement="right" title="Edit Description">DSA DSA DSA DSA DSA </a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="span5">
<div class="box box-color box-bordered">
<div class="box-title">
<h3><i class="icon-th-list"></i> Hi</h3>
</div>
<div class="box-content nopadding">Hello Hi Hello Hi Hello Hi</div>
</div>
</div>
</div>
DEMO FIDDLE
I know this is somewhat of a late reply, but I was just struggling with this issue and solved it in a different way which may help other people.
X-editable is based on Bootstrap's Popover plugin, so adding container: 'body' to your .editable() settings (or any other container that is not within your overflow:hidden element) will also fix this problem.
This will most likely only work with the Bootstrap version of X-editable but I haven't checked that.
Edit:
Just add that container option..
$('#username').editable({
container: 'body',
type: 'text',
pk: 1,
url: '/post',
title: 'Enter username'
});
Hi the problem is that the tootltip is inside a table and with position:absolute so he was searching for his closest parent with position:relative to be positioned.
The parent that he finds is the div with class .collapse. And this class has the property
overflow:hidden;
You have two solutions with css.
One type this in your css. Enables the view of the overflow in the div.
div.collapse {
overflow:visible;
}
Two type this in your css. Remove this div as the relative parent.
div.collapse {
position:static;
}
Your Fiddle http://jsfiddle.net/kGQ2R/6/