JavaScript only changes text of first iteration with thymeleaf - javascript

I hope you are all well.
I have a school assignment, and I want to dynamically be able to change the name of a 'project'. This assignment is about projects. The way I've done it right now works with the first 'project' from a list of 'projects' iterated through with thymeleaf. I'm aware that what I've done right now is absolutely bad code behavior, but we have had no teaching in JS yet. But I really wanted this feature.
I don't know how to make this work for each project preview, right now it works for the first preview, but for the rest it just erases the project name from database. (see picture)
<div class="projects" th:each="projectNames : ${listOfProjects}">
<form action="deleteProjectPost" method="post">
<input type="hidden" th:value="${projectNames.projectID}" name="deleteID">
<input type="image" src="delete.png" alt="Submit" align="right" class="deleteProject" onclick="return confirm('Are you sure that you want to delete this project?')">
</form>
<form action="/editProjName" method="post">
<input type="hidden" name="projectID" th:value="${projectNames.projectID}">
<input type="hidden" id="oldName" th:value="${projectNames.projectName}">
<input type="hidden" id="newName" name="projectName">
<input type="image" src="edit.png" alt="Submit" onclick="change_text()" align="right" class="editProject">
</form>
<form action="/projectPost" method="post">
<input class="projectInfo" name="projectID" type="text" th:value="'Project No.: ' + ${projectNames.projectID}" readonly="readonly">
<input class="projectInfo" type="text" th:value="'Project name: ' + ${projectNames.projectName}" readonly="readonly">
<input class="projectInfo" type="text" th:value="${projectNames.projectStartDate} + ' - ' + ${projectNames.projectEndDate}" readonly="readonly">
<input type="submit" value="OPEN" class="openProject">
</form>
</div>
<script>
function change_text() {
var changedText;
var projectName = prompt("Please enter name of project:");
var oldName = document.getElementById("oldName").value;
if (projectName === null || projectName === "") {
changedText = oldName;
} else {
changedText = projectName;
}
document.getElementById("newName").value = changedText;
}
</script>
First form in HTML is the red cross to delete an entire 'project'. Second form is what is intended to change the name displayed on the 'project preview', but only works on first preview and deletes project name from the rest. Last form is the actual preview. I couldn't find another way to have multiple forms and do different POSTS while working with Java Spring and Thymeleaf.
My wish is to make the change_text() function work for each 'project preview'
Best regards!

function change_text(imageInput) {
var changedText;
var projectName = prompt("Please enter name of project:");
var oldName = imageInput.parentNode.querySelector('.old-name').value;
if (projectName === null || projectName === "") {
changedText = oldName;
} else {
changedText = projectName;
}
imageInput.parentNode.querySelector('.new-name').value = changedText;
}
<form action="/editProjName" method="post">
<input type="hidden" name="projectID" th:value="${projectNames.projectID}">
<input type="hidden" class="old-name" id="oldName" th:value="${projectNames.projectName}">
<input type="hidden" class="new-name" id="newName" name="projectName">
<input type="image" src="edit.png" alt="Submit" onclick="change_text(this)" align="right" class="editProject">
</form>
Ok so I made a few changes. First, notice the inputs with oldName and newName now have classes on them. These can be repeated. If you are not using the ids for anything other than the script, you should remove them. Otherwise if you have styling rules for them you should consider changing those CSS rules to use the class instead so you can remove the invalid repeating ids.
Secondly, the onlick of the image now passes in this. What that does is it passes in the actual input that the user clicked, so you have some context into which form element the user is interacting with.
Then looking at the logic, the method now accepts in imageInput which is the this from the onclick.
Using imageInput.parentNode we go up the DOM Tree to the parent element of the input, which is the form in this case. We can then turn around and use querySelector to find the other element in the form we want to manipulate. And it will only find the element in our particular form because that is what we are selecting off of.

Related

Python-requests module, post two "values" to renew&scrape website

The first part was already answered, however, EDIT isn't.
I am using python and the requests module to scrape a website. Therefore I have to “click” a Renew-Button, which is a link(href) wrapped in an image “pat_renewmark.gif”.
html
<form name="checkout_form" method="POST" id="checkout_form">
<input type="HIDDEN" id="checkoutpagecmd">
<a href="#" onclick="return submitCheckout( 'sortByCheckoutDate', 'bycheckoutdate' )">
<img src="/screens/pat_sortbychkout.gif" alt="SORT BY DATE CHECKED OUT" border="0">
</a>
<input type="HIDDEN" name="currentsortorder" value="current_duedate">
<a href="#" onclick="return submitCheckout( 'requestRenewSome', 'requestRenewSome' )">
<img src="/screens/pat_renewmark.gif" alt="RENEW SELECTED ITEMS" border="0">
</a>
</form>
javascript (submitCheckout)
function submitCheckout(buttonname, buttonvalue)
{
var oHiddenID;
oHiddenID = document.getElementById("checkoutpagecmd");
oHiddenID.name = buttonname;
oHiddenID.value = buttonvalue;
//c29364j/c1365070 - prevent the patron from submitting twice
var oButtonSpan;
oButtonSpan = document.getElementById("checkoutbuttons0");
if (oButtonSpan) oButtonSpan.style.display = "none";
oButtonSpan = document.getElementById("checkoutbuttons1");
if (oButtonSpan) oButtonSpan.style.display = "none";
document.getElementById("checkout_form").submit();
return true;
}
Apparently submitCheckout passes .name and value, which are both assigned to ”requestRenewSome”’, to the hidden input with theid=“checkoutpagecmd”`.
I’ve worked with the requests module before and I am able to handle a simple username&password input , for example:
html
<div class="formEntryArea">
<label for="extpatid">
<span class="formLabel">
Your username:
</span>
</label>
<input name="extpatid" id="extpatid" value="" size="20" maxlength="40">
<label for="extpatpw">
<span class="formLabel">
Your password:
</span>
</label>
<input name="extpatpw" id="extpatpw" type="PASSWORD" value="" size="20" maxlength="40">
</div>
python
import requests
with requests.Session() as c:
LOGIN_URL = "https://example.com"
USERNAME = “XXXXX”
PASSWORD = “YYYYY”
source = c.get(LOGIN_URL)
data_load = dict(extpatid=USERNAME,extpatpw=PASSWORD)
head_load = dict(referer=LOGIN_URL)
c.post(LOGIN_URL, data=data_load, headers=head_load)
However, here c.post is handling only one “value” per input (either USERNAME or PASSWORD) and no javascript code is included.
As it seems, for the problem above I somehow have to post the two attributes/strings
.name = 'requestRenewSome'
.value = 'requestRenewSome'
? Or is the approach completely different to the example I attached?
EDIT
The answer from matino (or the comment from t.m.adam) solves the problem! Unfortunately the User then has to approve that he is sure he wants to renew by clicking a YES button.
html
<form name="checkout_form" method="POST" id="checkout_form">
<input type="HIDDEN" id="checkoutpagecmd">
<input type="HIDDEN" name="currentsortorder" value="current_duedate">
<span id="checkoutbuttons0">
<input type="SUBMIT" name="renewsome" value="YES">
<input type="SUBMIT" name="donothing" value="NO">
</span>
</form>
I therefore added 'renewsome': 'YES'to the data_load dictionary, but thats not enough. I don't know the value for the hidden input/s? id=checkoutpagecmd and/or? name=currentsortorder but couldn't find any answer on how to proceed.
P.S. I know it's actually a knew question, and I'm going to separate it, if it's getting answered.
What the javascript code actually does is dynamically assigning name and value to the hidden input. So in the end there can be 2 cases:
<input type="hidden" id="checkoutpagecmd" name="sortByCheckoutDate" value= "bycheckoutdate">
or
<input type="hidden" id="checkoutpagecmd" name="requestRenewSome" value= "requestRenewSome">
Knowing that, you can send http request like this:
requests.post(url, data={'sortByCheckoutDate': 'bycheckoutdate'}) # 1st case
requests.post(url, data={'requestRenewSome': 'requestRenewSome'}) # 2nd case

Validating Dynamically Added Form Inputs - Vanilla JS

I'm building a multipage form. On a few of the form's pages, I have questions that allow the user to add inputs dynamically if they need to add a job, or an award, etcetera. Here's what I'd like to do/what I have done so far.
What I Want to Do:
As the user adds fields dynamically, I want to validate those fields to make sure they have been filled in, and they are not just trying to move to the next page of the form with empty inputs.
After all the fields are successfully validated, a "Next" button at the bottom of the page, which up until this point was disabled, will become reenabled.
What I know How To Do
With some help, I've been able to workout a validation pattern for the inputs that are not dynamically added (such as First Name, Last Name) and I can extend this same logic to the first set of inputs that are not added dynamically. I have also worked out how to re-enable the "Next" button once all fields are good.
What I do Not Know How To Do
How do I write a function that extends the logic of the simple validation test to also check for dynamically added iterations.
http://codepen.io/theodore_steiner/pen/gwKAQX
var i = 0;
function addJob()
{
//if(i <= 1)
//{
i++;
var div = document.createElement("div");
div.innerHTML = '<input type="text" class="three-lines" placeholder="School Board" name="schoolBoard_'+i+'"> <input type="text" class="three-lines" placeholder="Position" name="position_'+i+'"> <input type="date" class="three-lines" name="years_'+i+'"> <input type="button" value="-" onclick="removeJob(this)">';
document.getElementById("employmentHistory").appendChild(div);
//}
}
function removeJob(div)
{
document.getElementById("employmentHistory").removeChild(div.parentNode);
i--;
};
function checkPage2()
{
var schoolBoard_1 = document.getElementById("schoolBoard_1").value;
if(!schoolBoard_1.match(/^[a-zA-Z]*$/))
{
console.log("something is wrong");
}
else
{
console.log("Working");
}
};
<div id="page2-content">
<div class="input-group" id="previousTeachingExperience">
<p class="subtitleDirection">Please list in chronological order, beginning with your most recent, any and all full-time or part-time teaching positions you have held.</p>
<div class="clearFix"></div>
<label id="teachingExpierience">Teaching Experience *</label>
<div id="employmentHistory">
<input type="text" class="three-lines" name="schoolBoard_1" id="schoolBoard_1" placeholder="School Board" onblur="this.placeholder='School Board'" onfocus="this.placeholder=''" onkeyup="checkPage2()" />
<input type="text" class="three-lines" name="position_1" placeholder="Position" onblur="this.placeholder='Position'" onfocus="this.placeholder=''" onkeyup="checkPage2()" />
<input type="date" class="three-lines" name="years_1" />
<input type="button" name="myButton" onclick="addJob()" value="+" />
</div>
</div><!--end of previousTeachingExperience Div -->
Instead of trying to validate each individual input element, I would recommend trying to validate them all at once. I believe that is what your checkPage2 function is doing.
You can add the onBlur event handler or the onKeyUp event handler you are currently using to all added inputs to run your form wide validation. This has the effect of checking each individual form element if it is valid so you know for sure you can enable the submit button.
Lastly, when removeJob is called, you should also run the form wide validation. It would look something like this:
function addJob()
{
i++;
var div = document.createElement("div");
div.innerHTML = '<input type="text" class="three-lines" placeholder="School Board" name="schoolBoard_'+i+'" onkeyup="checkPage2()"> <input type="text" class="three-lines" placeholder="Position" name="position_'+i+'" onkeyup="checkPage2()"> <input type="date" class="three-lines" name="years_'+i+'" onkeyup="checkPage2()"> <input type="button" value="-" onclick="removeJob(this)">';
document.getElementById("employmentHistory").appendChild(div);
}
function removeJob(div)
{
document.getElementById("employmentHistory").removeChild(div.parentNode);
i--;
checkPage2();
};
For every element that you make with document.createElement(...), you can bind to the onchange event of the input element, and then perform your validation.
Here's an updated version of your CodePen.
For example:
HTML
<div id="container">
</div>
Javascript
var container = document.getElementById("container");
var inputElement = document.createElement("input");
inputElement.type = "text";
inputElement.onchange = function(e){
console.log("Do validation!");
};
container.appendChild(inputElement);
In this case I'm directly creating the input element so I have access to its onchange property, but you can easily also create a wrapping div and append the inputElement to that.
Note: Depending on the freqency in which you want the validation to fire, you could bind to the keyup event instead, which fires every time the user releases a key while typing in the box, IE:
inputElement.addEventListener("keyup", function(e){
console.log("Do validation!");
});

get name of hidden form

What i want to do is get the name of the hidden form which in this case is named:6ca3787zz7n149b2d286qs777dd8357b, the problem is, that form name always changes, the only thing that is the same is its value, which is 1, well 99% of the time, the only thing that is 100% the same that i guess could be somehow used to retrieve the form name is:L2ZvcnVtcy8 which is just above it. I am also attempting to do this via running javascript manually on the browser (chrome), so having that in mind where the javascript code is run through the url bar like this javascript:codegoeshere, how can i get the form name, -->(6ca3787zz7n149b2d286qs777dd8357b)?
<form action="index.php?feature=xxxxxx" method="post" name="login">
<input type="submit" name="submit" class="button" value="Logout" />
<input type="hidden" name="option" value="username" />
<input type="hidden" name="task" value="logout" />
<input type="hidden" name="return" value="L2ZvcnVtcy8=" />
<input type="hidden" name="6ca3787zz7n149b2d286qs777dd8357b" value="1" /> </form>
</li>
Check all the solutions below in this fiddle.
Some possibilities:
Assuming there is only one element with the name login and that element is the <form>, you can use:
document.getElementsByName('login')[0].getElementsByTagName('input')[4].name
If the return <input> has a fixed name attribute, then this should work (the additional .nextSibling is because there is a text node between them):
document.getElementsByName('return')[0].nextSibling.nextSibling.name
If any other of of those <input>s has a fixed name, you can use (in the example I take the <input> with name=task):
document.getElementsByName('task')[0].parentNode.getElementsByTagName('input')[4].name);
If all you really have is that fixed value, you'll have to use a for loop through all the <input>s:
var lastResortName = (function () { for(var i=0, ipts = document.getElementsByTagName('input'), n = ipts.length; i < n; i++) { if (ipts[i].value === "L2ZvcnVtcy8=") return ipts[i+1].name; } })();
Note: If there are duplicated values for the mentioned name attributes, test with the index ([0], [1], [2] and so on) until you find the expected elements.
That's really easy if you use JQuery:
$('input[type="hidden"]:eq(3)').attr('name')
Here your code running:
http://jsfiddle.net/7CHYa/

How do I replace part of the value of attributes for a set of elements in jQuery?

I am trying to replace a series of 'for' attributes of labels based on their current contents.
The application is using AJAX to add an item to an invoice without refreshing the page. Upon receiving notification of a successful item add, my script should replace all the labels in the form whose 'for' attribute ends with '-new' with the same attribute minus the '-new' and adding ('-' + itemValue), where itemValue is the item Id of the invoice item that was added.
I know how to select all the labels I want to change at once:
jQuery('label[for$=new]')
I know how to get their 'for' attribute:
jQuery('label[for$=new]').attr('for')
I tried the JavaScript replace method:
jQuery('label[for$=new]').attr('for').replace(/-new/,itemValue)
But that appears to select each label's 'for' attribute, replace the text, and pass the replaced text back (to nothing), since I don't know how to identify the labels that have the 'for' attribute I want to replace.
Here's some sample HTML:
<form id="InvoiceItemsForm-1" action="<?=$_SERVER['PHP_SELF'];?>" method="post" name="InvoiceItemsForm-1" onsubmit="return false">
<div id="InvoiceItem-new-1" class="InvoiceItem">
<label for="InvoiceItemNumber-new">New Invoice Item Number: </label>
<input id="InvoiceItemNumber-new" class="InvoiceItemNumber" type="text" value="" name="InvoiceItemNumber-new">
<label for="InvoiceItemDescription-new">Item Description: </label>
<input id="InvoiceItemDescription-new" class="InvoiceItemDescription" type="text" value="" name="InvoiceItemDescription-new">
<label for="InvoiceItemAmount-new">Item Amount: </label>
<input id="InvoiceItemAmount-new" class="InvoiceItemAmount" type="text" value="" name="InvoiceItemAmount-new">
<input id="addInvoiceItem-1" width="25" type="image" height="25" src="/payapp/images/greenplus.th.png" alt="Add New Invoice Item" onclick="addInvoiceItemButtonPushed(this)" value="invoiceItem">
</div>
<button id="CloseInvoice-1" onclick="closeInvoice(this)" type="button">Close Invoice</button>
</form>
Once I get this to work, I'm going to replace all the ids for all the inputs. Same problem. I imagine the solution looks something like this:
jQuery('input[id$=new]').attr('id').replace(/-new/,itemValue)
I just cannot figure out the syntax for this at all.
No need to use .each() ... the .attr() method accepts a function as the second parameter that returns the new value to be used as replacement
jQuery('label[for$=new]').attr('for', function(index, currentValue){
return currentValue.replace(/-new/,'-' + itemValue);
});
If I may, why not just put the input tag inside the label tag? That way, you won't need a for attribute inside the label tag.
Next, a better way to accomplish what you're trying to do would be to use the invoice ID number as the ID for the surrounding div, and add a 'new` class for "new" invoice entries.
So your form would look something like this:
<form id="InvoiceItemsForm-1" action="<?=$_SERVER['PHP_SELF']" method="post" name="InvoiceItemsForm-1" onsubmit="return false">
<div class="InvoiceItem new">
<label>New Invoice Item Number: <input class="InvoiceItemNumber" type="text" value="" name="InvoiceItemNumber"></label>
<label>Item Description: <input class="InvoiceItemDescription" type="text" value="" name="InvoiceItemDescription-new"></label>
<label for="InvoiceItemAmount-new">Item Amount: <input class="InvoiceItemAmount" type="text" value="" name="InvoiceItemAmount-new"></label>
<input id="addInvoiceItem-1" width="25" type="image" height="25" src="/payapp/images/greenplus.th.png" alt="Add New Invoice Item" onclick="addInvoiceItemButtonPushed(this)" value="invoiceItem">
</div>
<button id="CloseInvoice-1" onclick="closeInvoice(this)" type="button">Close Invoice</button>
</form>
You'll still have all the targetability you need to get the new invoice item field data, but now, you only have two things to do to convert from a "new" invoice row to an "existing" invoice item row: add an id attribute to the div and remove the new class, both of which jQuery will let you do quite easily.
Not sure I get the question, but something like:
var oldFor = $('label[for$=new]').attr('for');
var newFor = oldfor.replace(/-new/,itemValue);
$('label[for$=new]').attr('for', newFor);
.attr( attributeName, value )
attributeName = The name of the attribute to set.
value = A value to set for the attribute.
When selecting multiple elements, you will need to iterate:
$('label[for$=new]').each(function(index) {
$(this).attr('for', $(this).attr('for').replace(/-new/, '-' + itemValue));
});

Build URL from form fields with JavaScript or jQuery

I'm trying to create a URL builder form with JavaScript or jQuery.
Basically, it will take the value of the two form fields, add them to a preset URL and show it on a third field on submit.
The resulting URL might be http://example.com/index.php?variable1=12&variable2=56
Now, this isn't the "action" of the form and the application can't read a URL (to grab the variables), so it has to be done on the page.
The resulting URL will be shown in the field named "url".
Here's a sample of the form:
<form id="form1" name="form1" method="post" action="">
<p>
<label>Variable 1
<input type="text" name="variable1" id="variable1" />
</label>
</p>
<p>
<label>Variable 2
<input type="text" name="variable2" id="variable2" />
</label>
</p>
<p>
<label>URL
<input type="text" name="url" id="url" />
</label>
</p>
<p>
<input type="submit" name="button" id="button" value="Submit" />
</p>
</form>
jQuery has serialize which builds the query string values.
So if you want to do the entire form:
alert($("#form1").serialize());
If you want to do only a few fields, then just make the selector select those fields.
alert($("#variable1, #variable2").serialize());
Use something like...
var inputs = $('#form1').find('input[type=text]').not('#url');
var str = "http://www.base.url/path/file.ext?"
inputs.each(function (i, item) {
str += encodeURIComponent(item.name) + "=" + encodeURIComponent(item.value) + "&";
});
$('#url').val(str);
This will select all <input>s on in form1 with type='text', and concatenate them into a query string. See encodeURIComponent().
Orrrr.....you could just use .serialize(). Thank you, prodigitalson.
Something like the following should work:
var partFields = '#variable1,#variable2';
$(partFields).change(function(){
var url = 'static/URL/to/file.php?';
$('#url').val(url + $(partFields).serialize());
});
However, unless you want people to be able to override the URL, you might want to use a hidden field and a regular element for display and submission of the URL value in which case you'd have something like the following:
var partFields = '#variable1,#variable2';
$(partFields).change(function(){
var url = 'static/URL/to/file.php?';
var urlValue = url + $(partFields).serialize();
$('#url-display').text(urlValue); // Set the displaying element
$('#url').val(urlValue); // Set the hidden input value
});

Categories