0

On my JSP site I want to copy some html elements and rename their attributes to generate a dynamic form. Currently my javascript code looks like this:

function getTemplateHtml(templateType)
{
    <%-- Get current number of elements. --%>
    var len = $('.form-group').length;
    <%-- Clone the correct template. --%>
    var $html = $(".template-"+templateType).clone();
    <%-- Replace placeholders. --%>
    $html.find('[id="PLACEHOLDER.Type"]')[0].id="filters" + len + ".Type";
    $html.find('[name="PLACEHOLDER.Type"]')[0].name="filters[" + len + "].Type";
    $html.find('[id="PLACEHOLDER.Value"]')[0].id="filters" + len + ".Value";
    $html.find('[name="PLACEHOLDER.Value"]')[0].name="filters[" + len + "].Value";
    ...
    return $html.html();    
}

Since there are 20 attributes, the code is very long and hard to maintain. Is there a way to call something like .replace('PLACEHOLDER', 'filters' + len) on the entire $hmtl element?

5
  • 2
    It's not clear what you're asking. Are you saying there are 20 different things that may be where you have PLACEHOLDER above? Commented Mar 25, 2019 at 12:19
  • 1
    Please provide a minimal reproducible example Commented Mar 25, 2019 at 12:24
  • With 20 I mean Type, Value etc.. I currently have 20 lines with .find. However, in each line only the PLACEHOLDERis replaced. Thus, it could be replaced by a single line always replacing PLACEHOLDER with a value independent of the current attribute. Commented Mar 25, 2019 at 12:25
  • 1
    Likely no need to even have id on those elements and only need class. Also suspect that using classes would make this all a lot simpler both in targeting the elements as well as updating the attributes. Show an html sample Commented Mar 25, 2019 at 12:26
  • 1
    @Thanthla - Ah, okay, I've updated my answer to do that instead (it's very similar). Commented Mar 25, 2019 at 12:32

2 Answers 2

2

Using an attribute starts with selector and attr(attributeName, function) you could probably do something generic like:

$html.find('[name^="PLACEHOLDER"]').attr('name', function(i, existingName){
     return existingName.replace('PLACEHOLDER', 'filters[' + len +']');
});

I would get rid of the id completely and use class instead. Managing dynamic id's is almost always more trouble than it is worth

Sign up to request clarification or add additional context in comments.

4 Comments

I have choosen this solution, altghough @T.J. Crowder also had a nice approach. However, this solution was for me easier to understand/maintain in the future. I copied the code for id.
I use the spring form syntax <form:input path="dummy.Type" ...> which is replaced by ìd` and name autonmatically.
Am guessing the id is on same element and if so could change the id inside the same callback in by answer. Just do this.id = this.id.replace(... beffore the return
Note if you remove any of the rows you will end up with duplicate names unless you keep track of previous count
2

If you mean you could have 20 different attributes where you have Type and Value in your question, yes, you can readily do that work in a loop:

["id", "name"].forEach(function(prop) {
    $html.find('[' + prop + '*=PLACEHOLDER]').attr(prop, function() {
        var match = /PLACEHOLDER\.([A-Z]+)/i.exec(this[prop]);
        if (match) {
            this[prop] = "filters" + len + "." + match[1];
        }
    });
});

That looks for all elements with PLACEHOLDER in their id or name and updates the id or name with the replacement, taking the attribute name ("Type" or "Value", etc.) from the id or name.

Live Example:

var len = 27;
var $html = $("#template").clone();
["id", "name"].forEach(function(prop) {
    $html.find('[' + prop + '*=PLACEHOLDER]').attr(prop, function() {
        var match = /PLACEHOLDER\.([A-Z]+)/i.exec(this[prop]);
        if (match) {
            this[prop] = "filters" + len + "." + match[1];
        }
    });
});
console.log($html.html());
<div id="template">
<input id="PLACEHOLDER.Type">
<input name="PLACEHOLDER.Type">
<input id="PLACEHOLDER.Value">
<input name="PLACEHOLDER.Value">
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

It's simpler if we can assume the id and name are on the same element:

$html.find('[id*=PLACEHOLDER]').attr("id", function() {
    var match = /PLACEHOLDER\.([A-Z]+)/i.exec(this.id);
    if (match) {
        this.id = this.name = "filters" + len + "." + match[1];
    }
});

That looks for all elements with PLACEHOLDER in their id or name and updates the id or name with the replacement, taking the attribute name ("Type" or "Value", etc.) from the id or name.

Live Example:

var len = 27;
var $html = $("#template").clone();
$html.find('[id*=PLACEHOLDER]').attr("id", function() {
    var match = /PLACEHOLDER\.([A-Z]+)/i.exec(this.id);
    if (match) {
        this.id = this.name = "filters" + len + "." + match[1];
    }
});
console.log($html.html());
<div id="template">
<input id="PLACEHOLDER.Type">
<input name="PLACEHOLDER.Type">
<input id="PLACEHOLDER.Value">
<input name="PLACEHOLDER.Value">
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

7 Comments

So, I still need the list of attributes? If I add an attribute to the html, I also have to update the list. Is there no generic way to replace "all" PLACEHOLDERS independent of the attibutname? The for-loop, however, makes the code much cleaner.
@Thanthla - Ah, yes, that is possible. I'll update the answer.
@Thanthla - Updated to do that.
Also guessing the id and name are actually on same element
@Thanthla - Can I assume the id and name are the same on the same element? That's often how these things are, but...
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.