Okay so, I'm using Angular 1.5.7, and I'm trying to do some table rendering with ng-repeat and stuff. This is what my table markup looks like:
<table class="table table-hover">
<thead>
<tr>
<td>Property name</td>
<td>Property value</td>
</tr>
</thead>
<tbody>
<adm-preset-property
ng-repeat="(propertyName, definition) in
componentDefinition.component_properties"
property-name="propertyName"
property-value="component.component_properties"
property-definition="definition"></adm-preset-property>
</tbody>
</table>
The <adm-preset-property> directive has a replace: true property and is rendered from a root <tr></tr> tag.
Now the loop works fine, BUT, instead of the table rows being rendered inside the table body, where they are nested, they are rendered ABOVE the table. I end up with
<tr>
{{ content }}
</tr>
<tr>
{{ content }}
</tr>
<tr>
{{ content }}
</tr>
<table>...</table>
What's worse, I can't seem to reproduce this on JSFiddle. What am I doing wrong?
EDIT: As requested, here's the template for the <adm-preset-property>
Template:
<tr>
<td>
<span data-toggle="tooltip" ng-attr-title="{{ ::propertyDefinition.description }}">{{ ::propertyDefinition.name }}</span>
</td>
<td ng-switch="propertyDefinition.editor_type">
<div ng-switch-when="select">
<ui-select append-to-body="true" ng-model="propertyValue[propertyName]" theme="bootstrap">
<ui-select-match placeholder="Select option...">{{ $select.selected.value }}</ui-select-match>
<ui-select-choices repeat="option.key as (key, option) in propertyDefinition.editor_properties.options | filter:{'value':$select.search} track by $index"
ng-value="key">
{{ option.value | highlight: $select.search }}</ui-select-choices>
</ui-select>
</div>
<div ng-switch-when="boolean">
<input type="checkbox" ng-model="propertyValue[propertyName]">
</div>
<div ng-switch-when="float">
<input type="range" step="0.01" ng-model="propertyValue[propertyName]" min="{{propertyDefinition.editor_properties.min}}"
max="{{propertyDefinition.editor_properties.max}}"> {{ propertyValue[propertyName] }}
</div>
<div ng-switch-when="color">
<input type="color" style="width: 75%;" ng-model="propertyValue[propertyName]">
</div>
<div ng-switch-when="int">
<input type="number" style="width: 75%;" ng-model="propertyValue[propertyName]" min="{{propertyDefinition.editor_properties.min}}"
max="{{propertyDefinition.editor_properties.max}}"> <br/>
<small>{{::propertyDefinition.editor_properties.min}} - {{::propertyDefinition.editor_properties.max}}</small>
</div>
<div ng-switch-default>
<input type="text" style="width: 75%;" ng-bind="propertyValue[propertyName]" />
</div>
</td>
</tr>
Directive:
(function() {
"use strict";
angular
.module('adomee.admin')
.directive('admPresetProperty', admPresetProperty);
/* #ngInject */
function admPresetProperty($log)
{
return {
restrict: 'E',
replace: true,
scope: {
propertyName: '=',
propertyValue: '=',
propertyDefinition: '='
},
templateUrl: 'app/preset/components/preset-property.tmpl.html',
link: function($scope, $element, $attributes) {
if ($scope.propertyDefinition.editor_type === 'select' && typeof($scope.propertyDefinition.defaultValue) === 'number') {
$scope.propertyValue[$scope.propertyName] = String($scope.propertyDefinition.defaultValue);
}
}
}
}
})();
Okay, after some research and consulting with my boss, we have concluded that Angular, naturally, compiles the directive's template into the DOM after the primary markup has been loaded.
Since the table expects a <tr> tag followed by <td>, but it runs into my custom tag instead, it removes the custom tag and places it outside of the table, which then compiles to my template afterwards, resulting in table rows on top of the actual table.
What I did was:
Change restrict: 'E' to restrict: 'A' in the directive.
Remove the replace property from it.
Remove the root <tr> tag and leave two <td> tags.
Place the directive into the table onto a <tr> and ng-repeat it.
Here's what it looks like now.
<tr adm-preset-property
ng-repeat="(propertyName, definition) in componentDefinition.component_properties"
property-name="propertyName"
property-value="component.component_properties"
property-definition="definition"></tr>
Related
Working with some Jinja code in my Flask app, I have a
<table class="table table-hover">
<thead>
<th scope="col" class="text-primary">Name</th>
<th scope="col" class="text-primary">Description</th>
</thead>
<tbody class="text-secondary">
{% for item in char.inventory %}
<tr id="{{item.itemid}}_row">
<div>
<td id="{{item.itemid}}_name">{{item.name}}</td>
</div>
<div>
<td id="{{item.itemid}}_description">{{item.description}}</td>
</div>
<td class="text-right"><button id="{{item.itemid}}" class="btn btn-outline-info" onclick="itemeditor(this)">edit</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
A loop that generates a table that's formatted with some bootstrap. The button when clicked on, leads to some JQuery code that transforms the item and description table entries into text inputs, containing the values of the table entries.
function itemeditor(elem) {
self = $(elem);
itemid = self.attr("id");
itemnamenode = $("#" + itemid + "_name")
itemdescriptionnode = $("#" + itemid + "_description")
itemnamefield = $('<input type="text" style="display : inline;" size="50" class="form-control" />')
itemnamefield.val(itemnamenode.text())
itemdescfield = $(('<input type="text" style="display : inline;" size="50" class="form-control" />'))
itemdescfield.val(itemdescriptionnode.text())
itemnamenode.replaceWith(itemnamefield)
itemdescriptionnode.replaceWith(itemdescfield)
}
The issue is that when the JQuery updates the table entries with their text inputs, the text inputs default to talking up the full width of the table and going under each other rather than spawning next to each other, in the original location of the table entries.
Before the button gets clicked
After the button is clicked
How can I set up the Bootstrap/ CSS such that the text inputs line up with the table?
Thank you very much for all and any help
Your table is not correct.
You can't put div as a closest child of tr.
Let try with this
<tbody class="text-secondary">
{% for item in char.inventory %}
<tr id="{{item.itemid}}_row">
<td>
<div id="{{item.itemid}}_name">{{item.name}}</div>
</td>
<td>
<div id="{{item.itemid}}_description">{{item.description}}</div>
</td>
<td class="text-right"><button id="{{item.itemid}}" class="btn btn-outline-info"
onclick="itemeditor(this)">edit</button>
</td>
</tr>
{% endfor %}
</tbody>
I'm thinking another way.
You don't need to replace the element.
Try to use input only, disabled as default, and only enable it when in editing mode, and also rememeber to style disabled input as a text.
I'm using Blade to fill some tables with content but in some cases a table might end up empty when there is nothing to fill.
Here is part of the php / blade template:
<table class="table">
#isset ($content->client)
<tr>
<td>
Client:
</td>
<td class="text-right">
{{ $content->client }}
</td>
</tr>
#endisset
#isset ($content->published)
<tr>
<td>
Published:
</td>
<td class="text-right">
{{ $content->published }}
</td>
</tr>
#endisset
</table>
In case $content->client and $content->published are not set the result is something like:
<table class="table">
</table>
Is there a simple css way to remove the table entirely in these cases?
I'm familiar with the :empty selector but aparently that doesn't work if there are whitespaces in the tag :(
I would suggest not printing the table if either of the variables are empty.
<?php
if( isset($content->client) || isset($content->published))
{
// echo table
}
?>
Did you try :blank? It also selects whitespace while :empty does not.
I want the value in the controller to be displayed in two lines of the same column.
{{ngapp}}.controller("Controller", function($scope, $http, $modalInstance){
$scope.selected=[];
$scope.items=[
{
value:'Impact to Safety, regulatory compliance environment',
key:10,
color:'red'
},
{
value:'Reliability Impact',
key:9,
color:'brown'
}
]
});
code in html:
<div class="well form-group" >
<table class="table" cellspacing="1">
<tr>
<th>Rank</th>
<th>Criteria: Type of loss incurred</th>
</tr>
<tr ng-repeat="item in items" onclick="selected.item= item" ng-click="sel(item)">
<td ng-style="{ 'background-color': item.color }">{{item.key}}</td>
<td> {{item.value}} </td>
</tr>
</table>
//<label>{{selected.item}}</label>
{% endverbatim %}
</div>
I want the Value:'Impact to Safety' to be displayed in one line. And 'regulatory compliance environment' in a new line for the same column and the same key. Anybody can help? Thanks. I'm new here.
For other parts of the code, refer to this Question,
Display value in a button by linking two modals
You can use https://www.npmjs.com/package/angularjs-filters to do this.
Replace the ',' by '<br />' and it should appear on the next line.
{{item.value | string.replace : ',': '<br />'}}
I am trying to make a series of rows based off of an array of objects. i am trying to produce a series of columns displaying each property of the objects (each has the same properties), with rows showing the property values.
I am currently using the following code.
<div ng-controller="HomepageController" >
<!-- form holding the name -->
<form td-ui-grid-row ng-controller="HomepageController"
ng-submit="vm.addData()" class="form-inline party-form" ng-repeat="dataEntry in vm.dataList">
<div td-ui-grid-col="3xs" ng-repeat="dataContent in dataEntry">
dataContent:{{dataContent}}
</div>
</form>
</div>
vm.data is the following series of data: [{"name":"davis","phone":"11111111111"},{"name":"graeham","phone":"222222222222"},{"name":"eric","phone":"33333333333"}]
and i want to produce the table of vales to look like:
davis graeham eric
11111111111 222222222222 33333333333
however, I am getting the inverse:
davis 11111111111
graeham 222222222222
eric 33333333333
I simplified the code so that it is easier to look and work with:
<div ng-controller="HomepageController" >
<!-- form holding the name -->
<form td-ui-grid-row ng-controller="HomepageController" ng-submit="vm.addData()" class="form-inline party-form">
<table>
<tr>
<td ng-repeat="person in vm.dataList">
<input ng-model="vm.newData.name" type="text" class="form-control" placeholder="{{person.name}}" required>
</td>
</tr>
<tr>
<td ng-repeat="person in vm.dataList">
<input ng-model="vm.newData.name" type="text" class="form-control" placeholder="{{person.phone}}" required>
</td>
</tr>
</table>
</form>
</div>
This code is now showing the proper output format, however i need to be able to cycle through any number of object attributes
.directive('tdUiGridRow', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.addClass('td-row');
if (attrs.tdUiGridRow) {
element.addClass('td-row-type-'+attrs.tdUiGridRow);
}
}
};
})
Please do below. You would create two loops, one for name and one for phone.
<div><span ng-repeat="contact in vm.data">{{contact.name}}</span></div>
<div><span ng-repeat="contact in vm.data">{{contact.phone}}</span></div>
This simply requires looping through the data multiple times, and extracting one property each time.
<table>
<tr>
<td ng-repeat="person in data">{{person.name}}</td>
</tr>
<tr>
<td ng-repeat="person in data">{{person.phone}}</td>
</tr>
</table>
http://plnkr.co/edit/tXmaTmPuwbsN62cQLJuF?p=preview
I'm trying to iterate over lists with sublists, and printing them as <tr> without much success.
This code illustrates what i want to accomplish:
<table>
<tr>
<th>1</th>
<th>2</th>
<th>3</th>
</tr>
<span ng-repeat='x in [["a1","a2"],["b1","b2"],["c1","c2"]]'>
<tr>{{x.length}}<tr>
<span ng-repeat='y in x'>
<tr>{{y}}<tr>
</span>
</span>
</table>
I would expect this to show:
<table>
<tr>3</tr>
<tr>a1</tr>
<tr>a2</tr>
<tr>b1</tr>
// and so on..
</table>
what should i do to make this work? I want to be able to repeat without the need to put in spans..
Only table tags (td, th, tr, tbody...) inside of <table> tag are shown, you should add ng-repeat to <tr>
If you use angular1.2 or higher you can use ng-repeat-start and ng-repeat-end tags:
html:
<table ng-controller="apiCtrl">
<tr ng-repeat-start="item in foo" ng-init="first=item[0]">
<td>first: {{ first }}</td>
</tr>
<tr ng-repeat-end ng-init="last = item[1]">
<td>last: {{ last }}</td>
</tr>
</table>
js:
function apiCtrl($scope) {
$scope.foo = [
['one', 'uno'],
['two', 'dos'],
['three', 'tres']
];
}
Here is JSfiddle
Here is fiddle with nested lists
This question is really old and AngularDart has changed a lot in the meantime. We can use the <ng-container> tag to apply all kinds of directives to a group of tags which are to be repeated or put under an *ngIf and so forth. The <ng-container> tag will not appear in the DOM output, but its contents will be there and affected by the specified directive.
<table>
<ng-container *ngFor="let row of matrix">
<tr>
<ng-container *ngFor="let value of row">
<td>{{value}}</td>
</ng-container>
<tr>
</ng-container>
</table>
When your component.dart has:
List<List<int>> get matrix => [[1, 2, 3], [4, 5, 6]];