Skip to content
Advertisement

JavaScript only changes text of first iteration with thymeleaf

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)

Illustration of how its done right now

<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!

Advertisement

Answer

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.

Advertisement