Using $index for ng-model - javascript

I am building a SPA where one can add a table-row on button-click:
<!-- Table -->
<table>
<tr>
<th>Lieferscheinnummer</th>
<th>Stück</th>
</tr>
<tr ng-repeat="position in positions">
<td><input type="text"></td>
<td><input type="text"></td>
</tr>
</table>
<!-- button -->
<span ng-click="addPosition()"></span>
Controller
$scope.positions = ['1'];
$scope.addPosition = function(){
$scope.positions.push( $scope.positions.length + 1 );
}
Now I have to apply an unique ng-model to each <td> of every row in order to send the given input to my database.
I searched for a solution and stumbled over ng-repeat's $index.
Unfortunately, $index seems to be not available for element attributes:
<tr ng-repeat="position in positions">
<td><input type="text" ng-model="{{$index +1}}"></td> <!-- does not work -->
<td><input type="text"></td>
</tr>
How would I apply an unique ng-model to each row while using ng-repeat?

You could change your model. Currently, you are using the ng-repeat like a counter. You have a model that stores the elements - you are not using the elements in anyway, just making use of the number of elements in the list and looping that many times.
What you could instead do is have a list of unique models itself.
Considering that you are using it inside a table, each entry could have an ID field to uniquely identify each row.
Thus, your model would look something like this:
//Will contain the data entered in the table
$scope.tableData = [
{
id: 1,
data: ""
},
{
id: 2,
data: ""
}
];
//Will keep track of the last used ID
$scope.currentId = 2;
//Will add a record to the table each time it is called
$scope.addRecord = function () {
var newRecord = {
id: $scope.currentId++;
data: ""
};
$scope.tableData.push(newRecord);
};
In your view, you can now use tableData to loop over the actual data itself rather than the count of the records:
<tr ng-repeat="entry in tableData">
<td>
<input type="text" ng-model="entry.data">
</td>
</tr>
For another input, you could simply add another attribute to each record. ng-repeat will create a scope for each record so entry.data will always point to the data attribute for the record located at that row.
Note: For an ID, you may have to use another approach of generating unique Ids for large amounts of records. Simply increment a counter will not be the best approach.

Related

How to create a dynamic table for addition using Express and Handlebars

I am trying to create a table where the number given in the url for example:
localhost:8000/add/:num
where the num is value given and it will create a table with rows which should contain the sums of all possible numbers from 0 to :num.
server.js
app.get('/add/:num', function(req,res) {
console.log(Number(req.params.num)+ Number(5));
res.render('add.hbs', {
number_1: 5,
number_2: req.params.num,
sum: Number(req.params.num)+ Number(5)
});
});
add.hbs
{{#each users}}
<tr>
<td>
{{number_1}}
</td>
<td>
{{number_2}}
</td>
<td>
{{sum}}
</td>
</tr>
{{/each}}
Now I can render the HTML table but i cannot dynamically add rows when a specific number is given on the URL. So if the number is passed as 2, it should add 0 + 1 onto one row, 1 + 2 onto the next row. I know i need to create a helper function in order to render that on the .hbs file but i cant figure out the logic behind it.

How do I get specific values from checked rows in MVC razor view?

Ok, so I have this partial view (part of an MVC application) which just displays data from a view in the database.
#model IEnumerable<TransportPlanner.Models.TRANSPORT_PLANNER_VIEW>
<table>
<tr>
<th>#Html.CheckBox("HeaderCheck")</th>
<th>#Html.DisplayNameFor(model => model.Status)</th>
....
<th>#Html.DisplayNameFor(model => model.Volume)</th>
<th>#Html.DisplayNameFor(model => model.Weight)</th>
....
</tr>
#foreach (var item in Model) {
<tr>
<th>#Html.CheckBox("RowCheck")</th>
<td>#Html.DisplayFor(modelItem => item.Status)</td>
....
<td>#Html.DisplayFor(modelItem => item.Volume)</td>
<td>#Html.DisplayFor(modelItem => item.Weight)</td>
....
</tr>
}
</table>
I want to be able to find a way in which I can get the values for the Volume and Weight fields of only the checked rows (after checking them), and add them to get the total (which is displayed but not stored).
For example, once I get the results displayed on screen, and I check 3 rows (having the values of 'weight' as 5, 10 and 15), then value displayed should be '30' (sum of the weights). Similarly, if I remove the checkbox for the row having weight as '5', then the value displayed should be '25'.
My front end skills are almost non-existent, and I have scourged over the internet for nearly 12 hours but not found a way to do it. I know that I need to either use JavaScript (or some flavour of it like JQuery) or Ajax (if I need the values updates dynamically as I check/uncheck them).
What is the best way to achieve this, without updating my model? I don't have the luxury of time because I am the only developer at my workplace, and this is the first step of a huge task I need to complete in 3 weeks.
Your #Html.CheckBox("RowCheck") is generating invalid html (duplicate id attributes). Replace it with
<input type="checkbox" class="checkbox" />
Then add class names to the <td> elements for Volume and Weight
<td class="volume">#Html.DisplayFor(modelItem => item.Volume)</td>
<td class="weight">#Html.DisplayFor(modelItem => item.Weight)</td>
And assuming you want to display the totals in the table footer, add the following html to the <table> element (note you should also use the <thead> and <tbody> in your table
<table>
....
<tfoot>
<tr>
<td></td>
....
<td id="totalvolume"><td>
<td id="totalweight"><td>
....
</tr>
</tfoot>
</table>
Then you can use javascript/jquery to handle the change event of the checkboxes, and sum the values in each row. Using jquery:
$('.checkbox').change(function() {
var totalVolume = 0;
var totalWeight = 0;
var selected = $('.checkbox:checked'); // get the selected checkboxes
$.each(selected, function(index, item) { // loop through the selected checkboxes
var row = $(this).closest('tr'); // get the containing tr element
totalVolume += Number(row.find('.volume').text());
totalWeight += Number(row.find('.weight').text());
})
// display the totals
$('#totalvolume').text(totalVolume);
$('#totalweight').text(totalWeight);
});
Note, the above code assumes the values of properties Volume and Weight are numeric (without any formatting)

generate dropdown using angularJS controller

I am trying to dynamically add a dropdown using $sce.trustAsHtml() function but I am getting an empty list in the UI. Here is the code:
$scope.addRowtrain = function() {
$scope.locomotivesList = [{"name": "loco1", "value":"1"}, {"name": "loco2", "value":"2"}];
tableData[id] = $sce.trustAsHtml('CTRun'+counter++);
tableData[type] = $sce.trustAsHtml("<select data-ng-model='selectedLoco' data-ng-options='loco.name for loco in locomotivesList'></select>");
}
In the HTML, I want to render it as a table:
<table>
<tbody>
<tr ng-repeat="data in tableData track by $index">
<td ng-repeat="(k, p) in data track by $index"><span ng-bind-html=p>{{p}}</span></td>
</tr>
</tbody>
<a class="btn btn-danger" ng-click="addRowtrain()">Add Run</a>
...
</table
but it is displaying an empty table, please help
you are adding it dynamically you must not pass binding values instead pass Complete JSON object.
It's working with
this example
md-select in angular material

How to use two ng-repeat inside a particular tag

I have a json and inside this json there is an array that I want to iterate in <td>.
My functionality is like I have to create a table based on user input. User provides input for number of rows, input columns and output columns. So I have three arrays i.e $rootScope.input_columns, $rootScope.output_columns and $rootScope.rows which contain data provided by user to create the table. Now in input_columns there's an array which contains some information which I need to show on row cell. But with my current code it is giving me blank row.
Controller:
var app = angular.module('rulesApp');
app.controller('myController2', ['$scope', '$rootScope',function($scope, $rootScope){
var inputcol=[];
$rootScope.input_col=$scope.no_of_input;
$rootScope.output_col=$scope.no_of_output;
$rootScope.rows=$scope.no_of_row;
for(var i=0;i<$rootScope.input_col;i++){
inputcol.push({
id: inputcol.length,
dropped: false,
dataType:'',
name:'',
type:'input',
path:'',
rowCellValue:[],
rowCellValueOutput:[]
});
}$rootScope.input_columns=inputcol;//here i get input_columns json, Similarly json are made for output_columns and rows
$scope.statementSelected = function(branch, selected_branches) {
if(branch.selected) {
for(var i = 0; i < $rootScope.input_columns.length; i++) {
//Here i add an array inside input_columns.rowCellValue $rootScope.input_columns[i].rowCellValue.push($rootScope.rows[i].rowCellValue);
}
})
Adding the structure of input_columns
This is my html code:
<tbody>
<tr ng-repeat="row in rows"><!--It iterates on row json -->
<td><input type="checkbox"></td>
<!--Here i want that in row cells input_columns.rowCellValue data gets populate on row cell for input column -->
<td ng-repeat="col in input_columns.rowCellValue">{{(col == "") && "<enter data>" || (col.split("/")[3])}}</td>
<!--Here i want that in row cells output_columns.rowCellValueOutput data gets populate on row cell for output column -->
<td ng-repeat="col in output_columns.rowCellValueOutput" ng-click="openDialog($event)">{{(col == "") && "<enter data>" || (col.split("/")[3])}}</td>
</tr>
</tbody>
I want to get a structure like this
But I am getting blank rows
Please can anyone help me in this task. Is there an issue that I haven't iterated input_columns so i am not getting input_columns.rowCellValue values. How can I get the values of input_columns.rowCellValue in table columns? Is there anyway that I can use two ng repeat, with first ng-repeat i can get input_column value[col in input_column] and with second ng-repeat i can get rowCellValue[cell in col.rowCellValue].?
I was trying some solution and figured out one way to access rowCellValue:
This is the modified html code
<tbody>
<tr ng-repeat="row in rows"><!--It iterates on row json -->
<td><input type="checkbox"></td>
<!--Here i want that in row cells input_columns.rowCellValue data gets populate on row cell for input column -->
<!--here with $index i am getting first value of rowCellValue in entire column can i iterate it with using rows length -->
<td ng-repeat="col in input_columns">{{(col.rowCellValue[$index] == "") && "<enter data>" || (col.rowCellValue[$index].split("/")[3])}}</td>
<!--Here i want that in row cells output_columns.rowCellValueOutput data gets populate on row cell for output column -->
<td ng-repeat="col in output_columns" ng-click="openDialog($event)">{{(col.rowCellValueOuput[$index] == "") && "<enter data>" || (col.rowCellValueOutput[$index].split("/")[3])}}</td>
</tr>
</tbody>
this the actual table I want for input_column:
But I am getting this:
Can i iterate col.rowCellValueOutput[$index] with row length instead of $index? and for each column. If yes, please suggest some approach for this.
Have you tried putting this into a JSON object and looping through the JSON. It looks like what you are trying to do is, everytime a new row is created, the inputCol and outputCol would be trying to output everything for every row.
//pseudo code
ng-repeat row in rows
ng-repeat input in inputs
ng-repeat output in outputs
Everytime you loop through rows, all of inputs and outputs data will be outputted again, making every row the same.
If you made a JSON object and done something like,
ng-repeat row in rows
ng-repeat input in row.input
ng-repeat output in row.output
Your JSON would look like
var rows = [{ input: [ "row1", "col2" ], output: [ "col3", "col4" ] },
{ input: [ "row2", "col2" ], output: [ "col3", "col4" ] }];
I found a solution for my problem:
<td ng-repeat="col in input_columns" title="" id="{{col}}">{{(col.rowCellValue[$parent.$index] == "") && "<enter data>" || (col.rowCellValue[$parent.$index].split("/")[3])}}</td>
In controller structure of json was like:
input_column({
rowCellValue[
0:dic2317/fdgdfg3535/accViolation
1:dic2317/sdg3436dg/driver
})
I used $parent.$index for iterating with rows index.

How to get html table values from multiple columns with single checkbox and submit to servlet?

I have html data table. I want to get values from multiple columns with single checkbox and when click on submit button values should go to servlet. Please help how to do this?
function refile(){
$('#resend').click(function() {
$("input:checked").each(function () {
var id = $(this).attr("id");
var messagePayload = $('#'+id).val();
var messageType = $('#msgType'+id).val();
alert("Payload Alert:"+ messagePayload);
alert("MessageType Alert:"+ messageType);
$.ajax({
type: "POST",
url: "http://localhost:8080/InterfaceMonitoring/ResendServlet",
data: {
messagePayload:messagePayload,
messageType:messageType
}
});
});
});
}
<c:otherwise>
<c:forEach items="${msgs}" var="msg" varStatus="count">
<tr id="check">
<td>
<input type="checkbox" id ="payloadMsg${count.index}" name="payload" value="${msg.messagePayload}">
</td>
<td></td>
<td>${msg.dob}</td>
<td></td>
<td>${msg.name}</td>
<td></td>
<td>
<div class="accordion">
<h3>Payload</h3>
<div id="payloadMsg${count.index}">${msg.messagePayload}</div>
</div>
</td>
<td></td>
<td>
<div id="msgType${count.index}">${msg.messageType}</div>
</td>
</tr>
</c:forEach>
</c:otherwise>
The problem is the way you try to get messageType.
Since you're using the ID of the input element, and prefixing it with #msgType it results in #msgTypepayloadMsgX so that element will never be found.
And since it's a DIV you're looking for you should use .html() to get the content.
Try adding data-index="${count.index}" to each input[checkbox] and get it in the script using $(selector).data('index') so that you can query for $('#msgType' + index)
And you should not make an ajax request for each row. Instead store the payloadMessage and messageType in an object and send it all to the backend at once, after iterating all rows.
An example could be:
Javascript
function refile(){
$('#resend').click(function() {
var payloads = [];
$('input:checked').each(function () {
var $this = $(this),
index = $this.data('index'),
$type = $('#msgType' + index);
payloads.push({
messageType: $type.html(),
messagePayload: $this.val()
});
});
if (payloads.length === 0) {
return;
}
$.ajax({
type: 'POST',
url: 'http://localhost:8080/InterfaceMonitoring/ResendServlet',
data: {
'payload': payloads
}
});
});
}
HTML
<tr id="check">
<td><input type="checkbox" id="payloadMsg${count.index}" data-index="${count.index}" name="payload" value="${msg.messagePayload}"></td>
<td></td>
<td>${msg.dob}</td>
<td></td>
<td>${msg.name}</td>
<td></td>
<td>
<div class="accordion">
<h3>Payload</h3>
<!-- Note that this ID is conflicting with the input#payloadMsg${count.index} -->
<div id="payloadMsg${count.index}">${msg.messagePayload}</div>
</div>
</td>
<td></td>
<td>
<div id="msgType${count.index}">${msg.messageType}</div>
</td>
</tr>
So, from what I've seen, on the front-end, at least, your code SHOULD work, but you've made it REALLY complex. . . . more complicated than you need it to be, I think. Again, while it should work, simplifying it will mean that there are much fewer places in the code where something could go wrong.
I think the best way to do this is make it easy on yourself:
flag the <div> elements that you want to retrieve with a class value that you can use to get their values (rather than relying on the unique IDs)
make the "unique" identifier of the message at the highest level in the table as you can (in this case, the <tr>
simplify your HTML attributes . . . you've got a lot of duplicate data and excess identifiers in your table structure. Try something like this:
HTML
<c:otherwise>
<c:forEach items="${msgs}" var="msg" varStatus="count">
<tr id="payloadMsg${count.index}">
<td>
<input type="checkbox" name="payload">
</td>
<td></td>
<td class="msg-dob">${msg.dob}</td>
<td></td>
<td class="msg-name">${msg.name}</td>
<td></td>
<td>
<div class="accordion">
<h3>Payload</h3>
<div class="msg-payload">${msg.messagePayload}</div>
</div>
</td>
<td></td>
<td>
<div class="msg-type">${msg.messageType}</div>
</td>
</tr>
</c:forEach>
</c:otherwise>
Once you've set that up, you have a much more simple structure, with all of the values that you could ever need, clearly identified. Now, you can pretty easily you can pretty easily get to the values that you need, using jQuery . . . just update your existing code to be something like this:
$(document).ready(function() {
$('#resend').click(function() {
$("input:checked").each(function () {
var currRow = $(this).closest("tr");
var currPayload = currRow.find(".msg-payload").text();
var currType = currRow.find(".msg-type").text();
alert("Payload Alert:"+ currPayload );
alert("MessageType Alert:"+ currType );
$.ajax({
type: "POST",
url: "http://localhost:8080/InterfaceMonitoring/ResendServlet",
data: {
messagePayload: currPayload,
messageType: currType
}
});
});
});
});
NOTE: You were using .val() instead of .text() to retrieve the text in the "type" <div> . . . .val() is only used with input elements.
Not knowing what you are doing on the back-end with this data, I can't really help you make sure that it is storing it correctly, but removing the reliance on the indexes to find the data that you want, should help simplify your logic a lot.
Also, if you ever want any other data from the row, you can capture it pretty easily now . . . for example:
var currMsg = currRow.attr("id");
var currDOB = currRow.find(".msg-dob").text();
var currName = currRow.find(".msg-name").text();
. . . after you have set the currRow value in your code, of course. :)
So, give that a try and see how things go. On the front-end, you should be good with this, at that point, you would need to just focus on the back-end and make sure that everything is working there.

Categories

Resources