Change uib-tabset content based on ng-table row click - javascript

I'm new to Angularjs, and web programming period, but I've made some progress on this.
So, I have an ng-table and I have ng-click working so that it changes the color of the row that is selected, but I also want the content of a tab to change based on the same click.
What I have so far:
index.html
<style>
.selected {
background-color:black;
color:white;
font-weight:bold;
}
</style>
<div ng-app="app" ng-controller="ctrl">
<table ng-table="tableParams" class="table table-bordered ">
<tr ng-repeat="user in $data" ng-class="{'selected':$index == selectedRow}" ng-click="setClickedRow($index, user.information)">
<td data-title="'First Name'">{{user.firstName}}</td>
<td data-title="'Last Name'">{{user.lastName}}</td>
</tr>
</table>
<uib-tabset type="pills">
<uib-tab ng-repeat="tab in tabs"
heading="{{tab.name}}"
active=tab.active>
{{tab.content}}
</uib-tab>
</uib-tabset>
</div>
myStuff.js
angular.module('app', ['ngTable'])
.controller('ctrl', function($scope, NgTableParams) {
$scope.names = [{"firstName": "John", "lastName": "Doe", "information": "Alpha"},
{ "firstName": "Mary", "lastName": "Manson", "information": "Bravo"},
{"firstName": "Bob", "lastName": "Smith", "information": "Charlie"}];
$scope.tableParams = new NgTableParams({
count: 20
}, {
data: $scope.names
});
$scope.setClickedRow = function(index, information){
$scope.selectedRow = index;
$scope.information = information;
//now I want to set the tab content to the value of information, my first guess was this below, that doesn't work.
//$scope.tabs.content = $scope.information;
}
$scope.tabs = [{id: 1, name: "heading", active:true, content: "no user selected."},
{id: 2, name: "heading2", active:false, content: "static content"}];
});
So, if you look at the setClickedRow function I have comments where I think this should go, as well as one of the things I tried, but I can't seem to get all the way there.
The goal is to just have the heading tab, which has the id or 1, to have whatever information is set to in the names array. So, for example, if the user selected the Mary Manson row, I would expect the heading tab to contain the content of "Alpha".
I have a jsfiddle, but I didn't actually get the tabset working in it b/c I'm new to jsfiddle too....but maybe it will help to show it.

If you know the index of the tab you need to set the content of, you can use $scope.tabs[someIndex].content = $scope.information;.
If not, but you know a property of the tab (like the name) you can use .filter() like this: $scope.tabs.filter(function(t){ return t.name == 'heading'; })[0].content = $scope.information;
If you can pass the tab in as a parameter to your method (which in this case it doesn't look like you can, but for reference) you can simply say tab.content = $scope.information;.

I didn't really understand the question but I observed that your ng-controller element is not wrapping the <uib-tabset> element. So the <uib-tabset> element doesn't even have the scope of the controller from which you are trying to pass the tabs. Try doing this. Might just solve your issue at least partially.
<div ng-app="app" ng-controller="ctrl">
<table ng-table="tableParams" class="table table-bordered ">
<tr ng-repeat="user in $data" ng-class="{'selected':$index == selectedRow}" ng-click="setClickedRow($index, user.information)">
<td data-title="'First Name'">{{user.firstName}}</td>
<td data-title="'Last Name'">{{user.lastName}}</td>
</tr>
</table>
<uib-tabset type="pills">
<uib-tab ng-repeat="tab in tabs"
heading="{{tab.name}}"
active=tab.active>
{{tab.content}}
</uib-tab>
</uib-tabset>
</div>

Related

ng-if and ng-class-even/odd doesn't work well together and won't get expected outout

Here,I am loading a json file and using ng-repeat I display json data into table form.I am adding following features to code.
checkboxes to add the two CSS:
Bubble CSS
text-danger [In built class]
when you click on those check boxes, the CSS is applied only to the even rows in the table.
Using the ng-if or ngHide/Show to display the User-info which have the gender : Male.
I use ng-if to fulfill condition because ng-if will remove elements from DOM. This means that all your handlers or anything else attached to those elements will be lost.
ng-show/ng-hide does not remove the elements from DOM. It uses CSS styles to hide/show elements.
I created Codepen demo for my problem.Here ng-if and ng-class-even doesn't give expected o/p.
HTML:
<body ng-app="module1" ng-controller="module1Ctrl as flight">
<div class="page-header">
<h1>Angular app</h1>
</div>
<div class="checkbox">
<label>
<input type="checkbox" ng-model="danger">
Something's Wrong
</label>
<label>
<input type="checkbox" ng-model="bubble">
Zoom In/Out
</label>
</div>
<table class="table table-striped table-bordered">
<tr>
<th>name</th>
<th>Birthdate</th>
<th>gender</th>
<th>father</th>
<th>mother</th>
</tr>
<tr ng-repeat="x in flightData"
ng-class-even ="{'text-danger':danger,'bubble': bubble}"
ng-if="x.sex=='f'">
<td>{{x.name}}</td>
<td>{{ x.born |date:'yyyy-MM-dd THH:mm:ss'}}</td>
<td>{{x.sex }}</td>
<td>{{x.father}}</td>
<td>{{x.mother}}</td>
</tr>
</table>
</div>
</body>
JS
var app=angular.module('module1',[]);
app.controller('module1Ctrl', function ($scope,$http) {
$scope.getDataFromServer = function () {
$http.get('http://codepen.io/timivey/pen/emQZYY.js').then(
function(res){
console.log(res.data);
$scope.flightData = res.data;
}
,function (err) {
console.log(err.message);
})
};
$scope.getDataFromServer();
$scope.showList='table';
});
Just a small change to Joel's answer. You no need to create a separate filter method.
<tr ng-repeat="x in flightData | filter:{sex:'f'}"
ng-class-even ="{'text-danger':danger,'bubble': bubble}">
There is nothing wrong with your code, but there is a small error with your understanding:
<tr ng-repeat="x in flightData"
ng-class-even ="{'text-danger':danger,'bubble': bubble}"
ng-if="x.sex=='f'">
The ng-if="x.sex == 'f' statement is omitting each <td> from display, but it does not remove them from the flightData array. ng-repeat is run for each item in the array, not for each item that is displayed.
If you add {{$index}} to each row of the table you will see that the order is not 0,1,2,3... it is 1,2,7,11,14...
If you remove the ng-if statement, you will see that every even row has correct class applied.
Instead of using ng-if to remove the males from the list, use a filter instead:
<tr ng-repeat="x in flightData | females"
ng-class-even ="{'text-danger':danger,'bubble': bubble}">
Append this filter to your controller statement in the JS code:
.filter('females', function() {
return function(input) {
var out = [];
angular.forEach(input, function(x) {
if(x.sex == 'f') {
out.push(x);
}
});
return out;
};
})
http://codepen.io/anon/pen/mABJyo
What this does is remove the males from the list before it runs the ng-repeat and will correctly output in the order 0,1,2,3...

how to bind data from dynamically named inputs inside a ng-repeat

my goal is to be able to copy data from a table row to another table row.
if the data from 2015 has not changed from 2016 the user needs a quick way of copying the values into the 2016 input fields. the models are dynamically created for these forms. the data you see in this image is assigned to a section. the input models are name 'price_min + section_id', price_max + section_id' , etc...
the history model does not have the section_id added to the end of the model names. so there needs to be a mapping function that i need help with. I need to map the history values to the current model convention and update the view with the values.
currently i have a click function that brings in the matched section history. here is a screen shot of what that looks like.
in that same function i have the 2016 object array with the current model naming convention.
i need to copy the history values into the inputArray. how i go about doing this, i dont know? I have complete control on how this works. and in the plunker you will see how i did this. if i need to change something else to make this work then that is ok. javascript, jquery, lodash, linq.js is currently being used in project.
working plunker
working plunker
$scope.copyHistoryData = function (section) {
var selected = Enumerable.From(sectionsHistory).Where("x => x.section_id == '" + section.section_id + "'").ToArray();
selected = selected[0];
var inputArry = section.sectionInputs;
};
I'm not sure why you use such complex data structure, but here is my take on it
$scope.copyHistoryData = function (section, input) {
var historyId=input.model.split('-')[0];
var historyVal=section.sectionHistory[section.sectionHistory.length-1][historyId];
$scope.model[input.model]=historyVal;
};
To fill all fields:
$scope.copyHistoryData = function (section) {
angular.forEach(section.sectionHistory[section.sectionHistory.length-1], function (historyVal, historyId) {
var inputModel=historyId+"-"+section.section_id;
$scope.model[inputModel]=historyVal;
});
};
http://plnkr.co/edit/OOEmgzKB1pqKjSJMayVF?p=preview
I agree with #ssh. The data structure is a mess. I think this is a better representation of what it should look like. Probably not the best but you shouldn't have to iterate through the data to then display it like that.
http://plnkr.co/C9DWV1dSvkk8lcYdm0An?p=preview
<div class="hpanel" ng-repeat="section in sections">
<div class="panel-body">
<div class="row">
<div class="col-xs-12">
<ul class="list-inline">
<li>
<h5>
<b>SecID</b>
</h5>
<span>{{section.section_id}}</span>
</li>
<li>
<h5>
<b>Section Name</b>
</h5>
<span>{{section.section_name}}</span>
</li>
</ul>
<hr/>
<button ng-click="section.new_section_history = section.section_history">copy row</button>
<table>
<tr>
<td ng-repeat="label in labelIndex">
{{label.label}}
</td>
</tr>
<tr>
<td ng-repeat="label in labelIndex">
{{section.section_history[label.index]}}
</td>
</tr>
<tr>
<td ng-repeat="label in labelIndex">
<input ng-model="section.new_section_history[label.index]"/>
</td>
</tr>
<tr>
<td ng-repeat="label in labelIndex">
<button ng-click="section.new_section_history[label.index] = section.section_history[label.index]">copy</button>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
I have checked your code, and I agree with #Steven Kaspar, the anchors in every row doesn't make much sense. I have solved it using jQuery (I know it doesn't follow your scheme with Angular, but it's another solution).
I have added a new <tr> to add a button inside it.
Check this out:
<tr>
<td colspan="10"><button class="copyRow">Copy complete row</button></td>
</tr>
And in the app.js:
$(document).on("click", ".copyRow", function(){
var $btn = $(this),
$tbody = $btn.parent().parent().parent(),
$trs = $tbody.find("tr");
$.each($trs.eq(0).find("td"), function(index, td){
$trs.eq(1).find("td").eq(index).find("input").val(parseFloat($(td).text().replace("$", "")));
});
})
Here is the updated plunker. I hope it helps

Pass object to isolated directive

When my application loads a function to get items from a server runs, this function get the title and Id of all items on the server,
then puts them in an array.
In my main html I have a table that displays this array, and when i click the title of an Item, I call another function (onView)
which gathers more information about that item from the server. This new information is passed to
a variable called '$scope.currentItem'.
I also have a directive called 'currentItem', this is used to display that item for the user.
myApp.directive('currentItem',function(){
return{
restrict:'E',
scope:{
data:'='
},
templateUrl: 'currentItem.html',
controller:function($scope){
}
};
});
To know if a user has clicked an item I have a boolean called isView, so when the function to gather more information runs
the isView is set to 'true'.
My html looks like this:
<div ng-app="myApp">
<hr>
<div ng-controller="appCtrl">
<div ng-hide="isView" class="col-md-12">
<table id="mainTable" ng-table="tableParams" class="table">
<tbody ng-repeat="item in items">
<tr>
<td id="Title" data-title="'Title'">
{{item.id}} |<a ng-click="onView(item.id)">{{item.title}}</a>
</td>
<td data-title="'Description'">
{{item.description | date:'dd-MM-yyyy'}}
</td>
<td data-title="'Created'">
{{item.created | date:'dd-MM-yyyy'}}
</td>
</tr>
</tbody>
</table>
</div>
<div ng-show="isView" class="col-md-12">
<current-item data="currentItem"></current-item>
</div>
</div>
</div>
This can't be the correct way to pass an object to a directive, seeing I always use the same 'currentItem' object.
How could I improve this, so that each object is isolated and editable in a seperate view?

How can a data-bind to an element within a Kendo-Knockout listview?

I have a rather sophisticated template for Kendo ListView using knockout-kendo.js bindings. It displays beautifully. My problem is that I need to use the visible and click bindings in parts of the template, but I can't get them to work. Below is a simplified version of my template. Basically, deleteButtonVisible determines whether the close button can be seen, and removeComp removes the item from the array.
<div class='template'>
<div >
<div style='display:inline-block' data-bind='visible: deleteButtonVisible, event: {click: $parent.removeComp}'>
<img src='../../../Img/dialog_close.png'></img>
</div>
<div class='embolden'>#= type#</div><div class='label1'> #= marketArea# </div>
<div class='label2'> #= address# </div>
<!-- more of the same -->
</div>
The view model:
function CompViewModel() {
var self = this;
self.compData = ko.observableArray().subscribeTo("compData");
self.template = kendo.template(//template in here);
self.removeComp = function (comp) {
//do something here
}
}
html:
<div class="row" >
<div class="col-md-12 centerouter" id="compDiv" >
<div class="centerinner" id="compListView" data-bind="kendoListView: {data: compData, template: template}"></div>
</div>
</div>
finally, sample data:
{
type: "Comparable",
marketArea: "",
address: "2327 Bristol St",
deleteButtonVisible: true
},
Take in count that the deleteButtonVisible must be a property on the viewModel linked to the view.You are not doing that right now. The click element can v¡be access from the outer scope of the binding and remove the $parent.He take the method from the viewmodel. Take in count that every thing that you take on the vie must be present on the view model for a easy access.

AngularJS - Building a dynamic table based on a json

Given a json like this:
{
"name": "john"
"colours": [{"id": 1, "name": "green"},{"id": 2, "name": "blue"}]
}
and two regular html inputs:
<input type="text" name="name" />
<input type="text" name="color" />
<input type="submit" value="submit" />
I need to build a table with all the possible variations, ex:
John green
John blue
That means that if a user continues adding values through the inputs new rows will appear building the new variations, for instance:
I also need to have available the id to handle it, and I need that when I add new values using the inputs for instance: "Peter" "Black", I need to autofill the id (colour id) dynamically like an auto increment in mysql, resulting in something like this:
{
"colours": […...{"id": 3, "name": "black"}]
}
Is that possible? Which options do I have for doing that with angular? I'm still thinking in the jQuery way and I would like to do it in the angular way.
I took a look to hg-repeat, and used it, but I'm not figuring out how to deliver the expected result, the only thing that come to my mind was to use nested ng-repeats, but it didm´t work.
Thanks so much in advance,
Guillermo
Just want to share with what I used so far to save your time.
Here are examples of hard-coded headers and dynamic headers (in case if don't care about data structure). In both cases I wrote some simple directive: customSort
customSort
.directive("customSort", function() {
return {
restrict: 'A',
transclude: true,
scope: {
order: '=',
sort: '='
},
template :
' <a ng-click="sort_by(order)" style="color: #555555;">'+
' <span ng-transclude></span>'+
' <i ng-class="selectedCls(order)"></i>'+
'</a>',
link: function(scope) {
// change sorting order
scope.sort_by = function(newSortingOrder) {
var sort = scope.sort;
if (sort.sortingOrder == newSortingOrder){
sort.reverse = !sort.reverse;
}
sort.sortingOrder = newSortingOrder;
};
scope.selectedCls = function(column) {
if(column == scope.sort.sortingOrder){
return ('icon-chevron-' + ((scope.sort.reverse) ? 'down' : 'up'));
}
else{
return'icon-sort'
}
};
}// end link
}
});
[1st option with static headers]
I used single ng-repeat
This is a good example in Fiddle (Notice, there is no jQuery library!)
<tbody>
<tr ng-repeat="item in pagedItems[currentPage] | orderBy:sortingOrder:reverse">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.description}}</td>
<td>{{item.field3}}</td>
<td>{{item.field4}}</td>
<td>{{item.field5}}</td>
</tr>
</tbody>
[2nd option with dynamic headers]
Demo 2: Fiddle
HTML
<table class="table table-striped table-condensed table-hover">
<thead>
<tr>
<th ng-repeat="header in table_headers"
class="{{header.name}}" custom-sort order="header.name" sort="sort"
>{{ header.name }}
</th>
</tr>
</thead>
<tfoot>
<td colspan="6">
<div class="pagination pull-right">
<ul>
<li ng-class="{disabled: currentPage == 0}">
<a href ng-click="prevPage()">« Prev</a>
</li>
<li ng-repeat="n in range(pagedItems.length, currentPage, currentPage + gap) "
ng-class="{active: n == currentPage}"
ng-click="setPage()">
<a href ng-bind="n + 1">1</a>
</li>
<li ng-class="{disabled: (currentPage) == pagedItems.length - 1}">
<a href ng-click="nextPage()">Next »</a>
</li>
</ul>
</div>
</td>
</tfoot>
<pre>pagedItems.length: {{pagedItems.length|json}}</pre>
<pre>currentPage: {{currentPage|json}}</pre>
<pre>currentPage: {{sort|json}}</pre>
<tbody>
<tr ng-repeat="item in pagedItems[currentPage] | orderBy:sort.sortingOrder:sort.reverse">
<td ng-repeat="val in item" ng-bind-html-unsafe="item[table_headers[$index].name]"></td>
</tr>
</tbody>
</table>
As a side note:
The ng-bind-html-unsafe is deprecated, so I used it only for Demo (2nd example). You welcome to edit.
Here's an example of one with dynamic columns and rows with angularJS: http://plnkr.co/edit/0fsRUp?p=preview
TGrid is another option that people don't usually find in a google search. If the other grids you find don't suit your needs, you can give it a try, its free
Check out this angular-table directive.
<table class="table table-striped table-condensed table-hover">
<thead>
<tr>
<th ng-repeat="header in headers | filter:headerFilter | orderBy:headerOrder" width="{{header.width}}">{{header.label}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="user in users" ng-class-odd="'trOdd'" ng-class-even="'trEven'" ng-dblclick="rowDoubleClicked(user)">
<td ng-repeat="(key,val) in user | orderBy:userOrder(key)">{{val}}</td>
</tr>
</tbody>
<tfoot>
</tfoot>
</table>
refer this https://gist.github.com/ebellinger/4399082
First off all I would like to thanks #MaximShoustin.
Thanks of you I have really nice table.
I provide some small modification in $scope.range and $scope.setPage.
In this way I have now possibility to go to the last page or come back to the first page.
Also when I'm going to next or prev page the navigation is changing when $scope.gap is crossing. And the current page is not always on first position. For me it's looking more nicer.
Here is the new fiddle example:
http://jsfiddle.net/qLBRZ/3/

Categories

Resources