Change style for element from ng-repeat - javascript

I am trying to uniqeley identify buttons in a tablerow, so I can change the style if one of them is clicked. Here is the table i am working on:
And here is the code:
<table class="table">
<thead>
<tr>
<th>Allergi navn</th>
<th>Allergi verdi</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="items in $ctrl.allergen">
<td>
<b>
{{items.Allergennavn}}
</b>
</td>
<td id="{{$index}}">
<button
id="tableButton"
type="button"
class="btn-grey"
ng-repeat="item in $ctrl.allergenVerdiType"
ng-click="$ctrl.allergiAssigned($index, items, item)"
>
<b>
{{item.Allergenverdi}}
</b>
</button>
<hr>
</td>
</tr>
</tbody>
</table>
And js:
ctrl.allergiAssigned = function($index, itemAllergen, itemAllergenType){
var index = $('button').index(this);
$(index, '#tableButton').css("background-color", "green");
}
I have tried several approaches to reference the specific button-element, using this, index, etc. I also need to verfiy that for every row, there is only one of the buttons that are selected.
I also tried to pass {{$index}} to get a unique identifier for the row, but jquery doesn't support the syntax.
UPDATE based on answers:
<table class="table">
<thead>
<tr>
<th>Allergi navn</th>
<th>Allergi verdi</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="items in $ctrl.allergen">
<td>
<b>
{{items.Allergennavn}}
</b>
</td>
<td id="{{$index}}">
<button id="tableButton" type="button"
class="btn-grey" ng-class="{activeBtn: item.active == true}"
ng-repeat="item in $ctrl.allergenVerdiType"
ng-click="$ctrl.select(items.type, item)">
{{item.AllergenverditypeKode}}</button>
<hr>
</td>
</tr>
</tbody>
</table>
ctrl.select = function(items, index) {
angular.forEach(items, function(item){
item.active=false;
});
index.active = true;
};
index returns undefined

You can change the CSS class based on the user action by using ng-class directive.
details
Code will be like that.
In CSS class :.activeButton:{background-color", "green"}
In button ng-click function : buttonClicked[$index]=true;
In Html button input:
..... ng-class="{'btn-grey':'btn-grey',
'activeButton':<add your condition like 'buttonClicked[$index]'>}"

To uniquely identify an element in nested ng-repeat, you can assign a unique Id to it by combining the $index from the parent loop and from the child loop as :
id="tableButton_{{$parent.$index}}_{{$index}}"
Now, pass the parent index and the child index to the event, fetch the element and change its css:
ng-click="assigned($parent.$index, $index)"
Below is a snippet of a sample data:
angular.module("app", []).controller("ctrl", function($scope) {
$scope.items = ["Item A", "Item B"];
$scope.buttonTypes = ["Btn1", "Btn2", "Btn3", "Btn4"];
$scope.assigned = function(parentIndex, childIndex) {
//Reset all buttons for one row
var parentBtns = "#" + parentIndex + " :button";
$(parentBtns).css("background", "transparent");
//Change the selected button css
var btn = "#tableButton_" + parentIndex + "_" + childIndex;
$(btn).css("background", "green");
};
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body ng-app="app" ng-controller="ctrl">
<table class="table">
<thead>
<tr>
<th>Allergi navn</th>
<th>Allergi verdi</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in items">
<td>
<b>{{item}}</b>
</td>
<td id="{{$index}}">
<button id="tableButton_{{$parent.$index}}_{{$index}}" type="button" class="btn-grey" ng-repeat="type in buttonTypes" ng-click="assigned($parent.$index, $index)">
<b>{{type}}</b>
</button>
<hr>
</td>
</tr>
</tbody>
</table>
</body>

You can try something like the below code, also you check you given working plunker example.
Template:
<button id="tableButton" type="button" class="defaultBtn" ng-class="{activeBtn: item.active}" ng-repeat="item in items.type" ng-click="select(items.type, item)">{{item.value}}</button>
Controller:
$scope.select= function(items, index) {
// You can remove this loop part if you don't want to reset your selection..
angular.forEach(items, function(item){
item.active=false;
});
index.active = true;
};

Related

Issues with appending Item to container

I am trying to append a new item and price (two input fields) to a container. I tried adding a class to the parent element and than adding both items at the same time.
For some reason I am not able to make this work.
'use strict';
$(document).ready(init);
function init(){
// $('#groupOne').on('click', '.item', clickHolder);
// $('#groupOne').on('click', '.item', clickCup);
$('#addButton').on('click', '.addItem', addFunction);
}
function addFunction(){
var item = $('.addItem').val();
console.log(item);
var placeIt = $('<td>' + item + '</td>');
('#groupOne').appendItem;
$('.addItem').val('');
}
<input type="text" class="addItem">
<input type="number" class="addItem">
<button id="addButton">Add</button>
</div>
<table id="groupOne">
<tr>
<th>Item</th>
<th>Price</th>
</tr>
<tr class="item">
<td>Banana</td>
<td>14.99</td>
</tr>
<tr class="item">
<td>Apple</td>
<td>5.99</td>
</tr>
<tr class="item">
<td>Tomato</td>
<td>8.99</td>
</tr>
</table>
You have some errors. First I'm not sure why you are using event delegation. Then you retrieve only the price of the item. Also you are using appendItem which is not javascript method as far as I know(I used jquery .append() method on my snippet because you have jquery object but you can use javascript appendChild on javascript object). I create the following snippet:
'use strict';
$(document).ready(init);
function init() {
//no need to use event delegation here. click event listener is enough
$('#addButton').on('click', addFunction);
}
function addFunction() {
//get item name
var itemName = $('.addItem:eq(0)').val();
//get item price
var itemPrice = $('.addItem:eq(1)').val();
//create jquery object
var placeIt = $('<tr><td>' + itemName + '</td><td>' + itemPrice + '</td></tr>');
//append it
$('#groupOne').append(placeIt);
$('.addItem').val('');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" class="addItem" />
<input type="number" class="addItem" />
<button id="addButton">Add</button>
<table id="groupOne">
<tr>
<th>Item</th>
<th>Price</th>
</tr>
<tr class="item">
<td>Banana</td>
<td>14.99</td>
</tr>
<tr class="item">
<td>Apple</td>
<td>5.99</td>
</tr>
<tr class="item">
<td>Tomato</td>
<td>8.99</td>
</tr>
</table>

Can you populate a table with Angular.js without hardcoding column names?

I have a simple Angular.js application that grabs tabular data from a mysql database and shows it in a simple bootstrap table. I’m using this code below to show the table column names without hardcoding them individually…
HTML:
<table class="table">
<thead>
<tr style="background:lightgrey">
<th ng-repeat="column in columns"> {{ column }} </th>
</tr>
</thead>
and in the controller I create ’$scope.columns’ with something like this…
var columnNames = function(dat) {
var columns = Object.keys(dat[0]).filter(function(key) {
if (dat[0].hasOwnProperty(key) && typeof key == 'string') {
return key;
}
});
return columns;
};
DataFactory.getTables(function(data) {
$scope.columns = columnNames(data);
$scope.tables = data;
});
And this works as expected and it’s great, but what about the the rest of the data.. So for example, the body of my table currently looks like this…
HTML:
<tbody>
<tr ng-repeat="x in tables ">
<td> {{ x.id}} </td>
<td> {{ x.name }} </td>
<td> {{ x.email }} </td>
<td> {{ x.company }} </td>
</tbody>
I’ve tried using two loops like this…
HTML:
<tbody>
<tr ng-repeat="x in tables">
<td ng-repeat=“column in columns”> {{ x.column }} </td>
</tr>
</tbody>
But this code doesn’t work, So is it possible to populate a table with angular without hardcoding the column names in HTML, and if so whats the most efficient way to do so?
You might want to try this https://jsfiddle.net/8w2sbs6L/.
<div data-ng-app="APP">
<table ng-controller="myController" border=1>
<thead>
<tr>
<td ng-repeat="column in columns">{{column}}</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="x in tables">
<td ng-repeat="column in columns">{{x[column]}}</td>
</tr>
</tbody>
</table>
</div>
<script>
'use strict';
angular.module('APP', [])
.controller('myController', ['$scope', function($scope){
$scope.tables = [
{
"column1":"row1-column1",
"column2":"row1-column2",
"column3":"row1-column3",
"column4":"row1-column4"
},
{
"column1":"row2-column1",
"column2":"row2-column2",
"column3":"row2-column3",
"column4":"row2-column4"
}
];
$scope.columns = [
"column1",
"column2",
"column3",
"column4"
];
}]);
</script>

Angularjs add element to DOM when clicking

I want to create a table which contains dynamic Content. When clicking on an element, the Details should Show up in the next line. So i creatied the following:
<table ng-controller="TestCtrl">
<tr ng-repeat-start="word in ['A', 'B', 'C']">
<td><!-- Some Information, Image etc --></td>
<td ng-click="showDetails(word)">{{word}}</td>
</tr>
<!-- This is only visible if necessary -->
<tr ng-repeat-end ng-show="currentDetail == word">
<td colspan="2" ng-attr-id="{{'Details' + word}}"></td>
</tr>
</table>
And I have the following js code:
angular.module('maApp', []).controller("TestCtrl", function($scope, $document, $compile){
$scope.showDetails = function(word){
var target = $document.find("Details" + word);
//I checked it - target is NOT null here
//target.html("<div>Test</div>");
//target.append("<div>Test</div>");
var el = $compile("<div>Test</div>")($scope);
target.append(el);
//Show tr
$scope.currentDetail = word;
};
});
I also tried the commented Solutions above but nothing of it works (The tr is showing up however). I guess there is something wrong with $document.find("Details" + word) but I don't know what.
Ultimately I want to add an <iframe> and the source would contain the word.
Does anybody see what I'm doing wrong here?
No need for weird non-angulary DOM manipulation: All you need is this.
HTML:
<table ng-controller="TestCtrl">
<tr ng-repeat-start="word in ['A', 'B', 'C']">
<td><!-- Some Information, Image etc --></td>
<td ng-click="showDetails(word)">{{word}}</td>
</tr>
<tr ng-show="currentDetail==word" ng-repeat-end>
<td colspan="2">Details {{word}}</td>
</tr>
</table>
JS:
angular.module('myApp', []).controller("TestCtrl", function($scope, $document, $compile){
$scope.showDetails = function(word) {
$scope.currentDetail = word;
};
});
http://jsfiddle.net/HB7LU/20074/
$document.find in jqlite is limited to tag name only. You have to add jquery for anything more.
See what is suported in the docs.
you have all you need built into angular already, you don't need the Javascript at all.
see this plunker example
<table style="width:100%;">
<thead style="background-color: lightgray;">
<tr>
<td style="width: 30px;"></td>
<td>
Name
</td>
<td>Gender</td>
</tr>
</thead>
<tbody>
<tr ng-repeat-start="person in people">
<td>
<button ng-if="person.expanded" ng-click="person.expanded = false">-</button>
<button ng-if="!person.expanded" ng-click="person.expanded = true">+</button>
</td>
<td>{{person.name}}</td>
<td>{{person.gender}}</td>
</tr>
<tr ng-if="person.expanded" ng-repeat-end="">
<td colspan="3">{{person.details}}</td>
</tr>
</tbody>
</table>

Sortable js none-jquery plugin sorts divs but not tables

I am using this Sortable plugin by Rubaxa, with the help of which I would like to sort my nested tables with the class of "block".
HTML
<table id="table">
<tbody>
<tr class="block">
<td>
<table>
<tr>
<td>item 1</td>
</tr>
</table>
</td>
</tr>
<tr class="block">
<td>
<table>
<tr>
<td>item 2</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
<div id="div">
<div class="block">1</div>
<div class="block">2</div>
</div>
JS
var el = document.getElementById('table'),
newEl = document.getElementById('div');
new Sortable(el, {
draggable: '.block'
});
new Sortable(newEl, {
draggable: '.block'
});
But I cannot get it to work with tables.
Does this plugin allow sorting only direct children? And is it because of the structure of tables it wont work? Or is it for some other reason?
jsFiddle link
It only works for first level children:
Solution
Ad an ID to tbody
<tbody id="rows">
Use this id to apply sort.
el = document.getElementById('rows')
Working example
I too had the same question and found a great answer here.
<tbody id="sortrows">
var sort = new Sortable(sortrows, {
onSort: function (evt) {
console.log(evt.oldIndex + ' -> ' + evt.newIndex);
document.getElementById('displayText').innerHTML=evt.oldIndex + ' -> ' + evt.newIndex;
} });
Adding a Working example

How to select a specific html node with a jquery selector and JavaScript?

I have the following html table:
<tbody>
<tr>
<td class="rich-tabpanel-content">
<table>
<tbody>
<tr>
<td>
<span class="bold">Overview</span>
</td>
</tr>
<tr>
<td>
<input class="titleInput" type="text"></input>
</td>
</tr>
<tr>
<td>
<span class="bold">Shorttext</span>
</td>
</tr>
<tr>
<td>
<textarea class="shorttextInput"></textarea>
</td>
</tr>
<tr>
<td>
<span class="bold">Longtext</span>
</td>
</tr>
<tr>
<td>
<textarea class="longtextInput"></textarea>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
Now i want to select these tags in DOM:
<span class="bold">Overview</span>
<span class="bold">Shorttext</span>
<span class="bold">Longtext</span>
I have written these line of JQuery and Java Script Code to change the value of these HTML Tags, but the command
"jQuery(value).parent().prev();"
doesn´t select the right html tag in the DOM:
jQuery('.titleInput').each(function(index, value) {
selectAndExpand(value);
}
function selectAndExpand(value) {
var captionCell = jQuery(value).parent().prev();
captionCell.empty();
var newCaption = '<span class="bold">' + "HERE IS MY NEW INPUTVALUE" + '</span>';
captionCell.append(newCaption);
};
How can i solve this problem?
It is important to navigate for example from the node
<textarea class="longtextInput"></textarea>
to
<span class="bold">Longtext</span>
or from
<input class="titleInput" type="text"></input>
to
<span class="bold">Overview</span>
Use:
$('.bold').each(function(){
$(this).html("HERE IS MY NEW INPUTVALUE")
});
Working Fiddle
With Javascript:
var elements = document.getElementsByClassName('bold');
console.log(elements[0]);
console.log(elements[1]);
console.log(elements[2]);
With jQuery:
var elements = $('.bold');
console.log(elements[0]);
console.log(elements[1]);
console.log(elements[2]);
or...
console.log($('td:contains("Overview")'));
console.log($('td:contains("Shorttext")'));
console.log($('td:contains("Longtext")'));
Cheers.
You can select them by class name (when the class name is the same, in your case "bold"):
$(".bold");
To select all textareas after them and set values to these "bold" - element use
var spans = $(".bold");
$.each(spans, function(index, item) {
var spanTd = $(item).closest("tr");
var value = $(spanTd).next().find("textarea").val();
if (value === undefined) { //if there aren't textarea - get textbox.
value = $(spanTd).next().find("input[type='text']").val();
}
$(item).html(value);
});
EDIT: Demo - http://jsfiddle.net/h9fpy/
use class selector in your case use $('.bold') to select the span class bold and you can easily navigate to prev and next like $('.bold').parent('tr').next().find('.bold'); and also give the bold class to your input elements so that we can easily navigate.

Categories

Resources