Repeat Control using jQuery - javascript

I'll probably lose reputation for asking this; but I've been trying infinite variations of code, and failing every time. So I'm reaching out.
I'm working on an aspx. It's all built, they just want some additional functionality.
We're using ScriptSharp to trans-compile to JavaScript.
Basically, we've got an HTML table. Each row in the table represents an invoice. One column in the table represents the amount due (call it amountDue) on the invoice. Another column on the table contains a textbox wherein the user may enter the amount to apply to the invoice (call it amountToPay). If the amounts differ, another column populates with a textbox, pre-populated with the difference between the amount due and the amount entered (call it difference). Following this column is another column with a drop-down list of reasons to explain the discrepancy (call it reason). The user may change the difference in the difference textbox. If that happens, a new additional difference textbox and a new additional reason drop-down list need to appear on the same row of the table, each under its appropriate column.
My first attempts duplicated controls geometrically, for example, going from two difference textboxes to eight. I figured that out.
Now every combination of jQuery functions I try either duplicates all the controls, or none of the controls. So, on difference change, either no new difference textbox is added, or the number of difference textboxes that exist is added. So if two exist, four result. If four exist, eight result.
Okay, here's some code.
Here are the two columns for difference and reason.
<td class="currency">
<div>
<input class="difference_textbox" type="text" value="0.00" style="display: none;" />
</div>
</td>
<td>
<div>
<select style="display: none;" class="adj_reason_select">
<option></option>
</select>
</div>
</td>
I'll skip the ScriptSharp and just list the trans-compiled JavaScript (debug version):
// Let this function represent the function called on `difference` change.
ReceivePayment._addAdjustment = function ReceivePayment$_addAdjustment(e) {
var self = $(e.target);
var customerInvoice = self.parents('.customer_invoice');
var amountPaidBox = customerInvoice.find('.amount_to_pay_input');
// ...
var amountPaidTD = amountPaidBox.closest('td');
var diffTextBoxTD = ReceivePayment._duplicateInputControl(amountPaidTD);
var adjReasonSelectTD = ReceivePayment._duplicateInputControl(diffTextBoxTD);
// ...
}
ReceivePayment._duplicateInputControl = function ReceivePayment$_duplicateInputControl(td) {
// This is very verbose so that I can stop at any point and
// examine what I've got.
var o = td.next(); // Grab the next td.
var divs = o.children(); // Grab the div(s) contained within the td.
var div = divs.last(); // Grab the last div within the td.
// And here's where all my gyrations occur, infinite permutations
// of jQuery calls, not one permutation of which has succeeded in
// adding the contents of the final div to the list of divs.
var d = div[0];
var html = d.outerHTML;
var s = html.toString();
div.add(s);
return o;
}
My attempts include calling after, insertAfter, html, clone, cloneNode, appendChild, and on, and on, on different objects, including divs, div, o, etc.
Part of my problem is that I've not worked with jQuery much. I know just enough to be dangerous. But surely this is possible. Given a td, find the following td. Within that td will be a list of one or more divs. Get the last of those divs, copy it, and append that copy to the list of divs. Done.
What, oh what, am I missing? Flame on.

I appear to have stumbled upon the solution after a shameful amount of time spent spinning my wheels. I gave up. Then, of course, it hit me:
ReceivePayment._duplicateInputControl = function ReceivePayment$_duplicateInputControl(td) {
// This is very verbose so that I can stop at any point and
// examine what I've got.
var o = td.next(); // Grab the next td.
var divs = o.children(); // Grab the div(s) contained within the td.
var div = divs.last(); // Grab the last div within the td.
o.append(div.clone());
return o;
}

Related

Turning an auto-expanding table row into a 'click to expand' row

I have a tablecompiled in Slim, which displays incoming messages in a row called 'events'.
My current issue is that this row automatically adjusts to expand to account for long messages, which creates a lopsided look if every 3rd message for example is quite long, but the rest are approximately one line of text.
I want to change this so that any string longer than 30 characters only displays the first line, and expands (aka reverts to it current format) upon clicking the row.
I however, can't think of the best way to approach this, and don't want to over-engineer a solution. What path would you suggest to achieve this?
table.slim
table.table.table-striped
thead.bg-white
tr
th = t('panel.home.show.event')
tbody.activities
- #activities.each do |activity|
tr
- activity_cell = cell(:activity, activity)
td.event
== activity_cell.subtitle
- if activity.deleted_by_slug.present?
code == link_to(activity.deleted_by_slug, activity_cell.path(:deleted_by_slug))
td
== activity_cell.state

Color cell according to condition

I have a table in which I have to set background color when the cell in header and cell in row appear as pair in a certain list in data source.
For example:
column : "AUD, USD"
row : "BRL, CZK"
in the cell of column AUD and row is BRL I check if exists in the list in datasource "AUD-BRL" and if so I need to color in a green
Now, I thought to do it in this way:
columns and rows will be in lists.
I go over both lists and then color in those indexes the cell.
So that I will have one function for whole table and not have to call from each cell to function (There are 1200 cells overall).
How can that be done?
The answer from Fede MG is correct.
If I understand your question correctly, you want to add a highlighting rule to all cells in the table detail row. Unfortunately I think it is a bit cumbersome to achieve this in BIRT.
I assume that your table has e.g. bindings like COL_VALUE_1, ..., COL_VALUE_9 for the cell values and COL_TITLE_1, ..., COL_TITLE_9 for the column headers.
Furthermore I assume a bit of experience with using Javascript in BIRT.
The way I do this like this:
For each detail cell I create a onCreate event script with code like this:
highlightDetailCell(this, row, 1);
... where 1 is the column number. E.g. this is the code for the first column, for the second column i replace the 1 with 2 and so on. One can quickly do this with copy&paste.
Next I implement the logic in a function inside the onInitialize script of the report like this:
function highlightDetailCell(item, row, colnum) {
var colTitle = row["COL_TITLE_" + colnum];
var colValue = row["COL_VALUE_" + colnum];
var highlight = use_your_logic_to_decide(colTitle, colValue);
if (highlight) {
item.get_Style().backgroundColor = "yellow";
}
}
This is the basic idea. If you want to add the script to many cells, it might be a lot of work to do this by hand. In fact it is possible to attach the call to the highlightDetailCell function with a script (of course, this is BIRT :-). You should read the documentation and just tinker with the Design Engine API (DE API for short).
But be warned that writing and debugging such a script may be even more work than doing the donkey work of adding and editing a one-liner to 1200 cells!
What I once did was basically this (in the onFactory event of the report item):
// This code is a simplified version that modifies just the first cell,
// However it should point you into the right direction.
// Some preparation
importPackage(Packages.org.eclipse.birt.report.model.api);
var myconfig = reportContext.getReportRunnable().getReportEngine().getConfig();
var de = DataEngine.newDataEngine( myconfig, null );
var elementFactory = reportContext.getDesignHandle().getElementFactory();
// Find the item you want to modify (in my case, a "Grid Item").
// Note that for tables, the structure is probably a bit different.
// E.G. tables have header, detail and footer rows,
// while grids just have rows.
var containerGrid = reportContext.getDesignHandle().findElement("Layout MATRIX");
// Get the first row
var row0 = containerGrid.getRows().get(0);
// Do something with the first cell (:
var cell = row0.getCells().get(0).getContent();
cell.setStringProperty("paddingTop", "1pt");
cell.setStringProperty("paddingLeft", "1pt");
cell.setStringProperty("paddingRight", "1pt");
cell.setStringProperty("paddingBottom", "1pt");
cell.setStringProperty("borderBottomColor", "#000000");
cell.setStringProperty("borderBottomStyle", "solid");
cell.setStringProperty("borderBottomWidth", "thin");
cell.setStringProperty("borderTopColor", "#000000");
cell.setStringProperty("borderTopStyle", "solid");
cell.setStringProperty("borderTopWidth", "thin");
cell.setStringProperty("borderLeftColor", "#000000");
cell.setStringProperty("borderLeftStyle", "solid");
cell.setStringProperty("borderLeftWidth", "thin");
cell.setStringProperty("borderRightColor", "#000000");
cell.setStringProperty("borderRightStyle", "solid");
cell.setStringProperty("borderRightWidth", "thin");
// When you're finished:
de.shutdown( );
Things are more complicated if you have to handle merged cells.
You could even add content to the cell (I created a whole matrix dynamically this way).
The script does not exactly what you want (add the script to each cell), but I leave this as an exercise...
It is also helpful to save the dynamically modified report design for opening in the designer, to see the outcome:
reportContext.getDesignHandle().saveAs("c:/temp/modified_report.rptdesign");
HTH
Go to the cell you want to format (applies also to elements like rows or columns), on the "Property Editor" go to "Highlights" and click "Add...". You'll get a dialog where you can enter a condition for the highlight and what styling to apply on the element if the condition is true.
Screenshot here

Swap Divs then swap selected option value between two select lists

The Problem:
Before I began adding the div swaps, I could only type into the left (from_value) input and the result of the calculations would be applied via ajax to the right (to_value) input.
I would like to allow the user to type into either box and have the results display in the opposite box they're typing in.
What I am doing to make this happen:
I am swapping the left div with the right div on mouseover of the to_value input. Here's the code i'm using to do the swap:
$.fn.swapWith = function (that) {
var $this = this;
var $that = $(that);
// create temporary placeholder
var $temp = $("<div>");
// 3-step swap
$this.before($temp);
$that.before($this);
$temp.after($that).remove();
return $this;
};
var leftSide = $('#left-side');
var rightSide = $('#right-side');
$('#to_value_input').on('mouseover', function () {
$(rightSide).swapWith(leftSide);
});
This effectively swaps the divs, bringing along with it ids and names of the inputs which retains functionality of my server-side script to perform calculations. As expected, the from_unit select list and to_unit select list are swapped and their values / displayed text are also swapped from one side to the other.
I would like to swap the values and text of the two select boxes either directly before or more likely, directly after the div swap so it appears as if nothing changed on screen.
Similar questions that I have reviewed:
How to swap values in select lists with jquery?
How to swap selected option in 2 select elements?
I have tried several variations of each of the provided solutions. This seems like it should be a fairly simple thing to do but I find myself stuck. Any further help would be greatly appreciated.
The full code base is available on github if you need to see it: https://github.com/pschudar/measurement-conversion
I have made minor changes to the code hosted there to accommodate the div swaps.

How to get value from selected input field (not using id)

I try to do simple code for guessing notes by ear. I have tabs with several empty input fields and you need to put right numbers in these fields according to certain melody (for guitar fretboard) . One button shows first note, another button checks whether you put right or wrong number and depend on it approves or erase your number.
I know how to check every input field using its id's but can i do it such way that when i push 2nd button it get value from selected input and compare it to its placeholder or value attribute?
It is my codepen
https://codepen.io/fukenist/pen/BxJRwW
Script part
function showfirst() {
document.getElementById("fst").value = "12"
}
function show1other() {
var snote = document.getElementById("scnd").value;
if (snote == 9 ){
document.getElementById("scnd").value = "9";
}
else {
document.getElementById("scnd").value = "";
}
}
You can use document.querySelectorAll() to get all your inputs and loop over them.
Sample:
// Get all inputs as an array (actually NodeList, to be precise; but it behaves similar to an array for this use case)
var inputs = document.querySelectorAll('input');
// Function to reveal the first input's value
function showFirst(){
inputs[0].value = inputs[0].dataset.v;
}
// Function to check all values and clear input if wrong
function checkAll(){
inputs.forEach(function(input){
if(input.dataset.v !== input.value){
// Wrong answer, clear input
input.value = '';
}
});
}
<input data-v="12" size="2" value=""/>
<input data-v="9" size="2" value=""/>
<input data-v="8" size="2" value=""/>
<br/>
<button onclick="showFirst()">Show First</button>
<button onclick="checkAll()">Check All</button>
Notes:
I have used data-v to store the correct answer instead of placeholder as that attribute has a semantically different meaning
It may be out of turn but my two cents: Writing out entire songs like this by hand may become tedious. Consider using a JSON string or something similar to map out the tabs and use a templating framework to align them.. Some things you may need to look out for while designing something like this : Alignment of notes (successive notes, simultaneous notes), timing of the song, special moves like slide, hammer on etc.
It may be a better idea to make the Guitar Strings be a background element (either as a background-image or as absolutely positioned overlapping divs) (so You don't have to worry about the lines going out of alignment)
Reference:
HTMLElement.dataset
document.querySelectorAll

JS/JQUERY: Moving numbered table rows up and down without losing user input

I have created a table in HTML, consisting of table rows in a tbody tag.
I've used a javascript code snippet from mredkj.com to be able to add rows and delete them, too. The rows are sorted and their rank is in the first TD (cell) in every TR (row).
Now I would like the add the functionality of being able to manually 'resort' the tablerows.
The problems are:
my javascript/jquery knowledge is
very limited
the ranks of tablerows
do not get updated(when you delete a row, the
rowranks get updated by the
'reorderRows function, but calling this function from within my jQuery does not seem to
sort out the problem)
the user's input in textarea's gets erased as soon as up or down button is clicked.
For example: user adds a TR, that gets added at the bottom of the current list of tablerows, fills in the textarea and desides that the row (s)he filled should be ranked first, so she clicks the up arrow a couple of times, until it's on top.
The rank of the row is now #1 and the input is still in the textarea's.
My questions are:
Does anyone know how I can make the
rows update their ranking when the
user moves the row?
How do I maintain the user's input?
Any help is very much appreciated and if you have any other suggestions, please share them.
Code here: http://jsbin.com/eyefu5/edit - for some reason, the moving up and down doesn't work in js bin, it does however when I run it in my browser.
I updated your code to do what I think you were trying to do: http://jsbin.com/eyefu5/9/
My primary changes were to the following swap logic:
function swap(a, b){
b.before(a);
reorderRows(document.getElementById(TABLE_NAME), 0);
}
function getParent(cell){ return $(cell).parent('tr'); }
$('#diagnosetabel').on('click', '.upArrow', function(){
var parent = getParent(this);
var prev = parent.prev('tr');
if(prev.length == 1){ swap(parent, prev); }
});
$('#diagnosetabel').on('click', '.downArrow', function(){
var parent = getParent(this);
var next = parent.next('tr');
if(next.length == 1){ swap(next, parent); }
});
The biggest difference is that I switched the swap code to using jQuery's before method, which should take care of just about everything for you. I also added a call to the reorderRows method which you were already using. At the moment it starts at the beginning and reorders all the numbers after the swap, but you could narrow this down as needed because you know the only two rows which were modified.
Hope that helps!

Categories