I have a todo list that I made with the help of Pranav Rustagi and Twisty. I still have a problem for which I can’t find a solution.
Between each text added, I want to add a separator (pipe). My problem is that when I delete the first element, the next element, which becomes the first one, has an unwanted pipe.
So how can I add a separator only if there is more than one element, and only if it’s not the first element ?
To reproduce the scenario: add a, b, c, and then delete a. You’ll see the pipe before the b still there. Is it better to imagine a pipe only if there is an element after?
One main issue here is the empty() inside the remove function. It doesn’t delete the span.output from the DOM so I cannot use first() or do something in css like :
.output:not(:first-of-type):before {
content:'|';
padding:0 5px;
}
I can’t use remove() instead of empty() either because I won’t be able to add a line again if I delete them all.
Any help would be appreciated.
$(function() {
$(".container").on('input', 'input[type=text]', function(event) {
var i = $(this).closest(".flex-row").index();
var v = (i == 0) ? $(this).val() : "|" + $(this).val();
$("#custom_wrapper .output").eq(i).html(v);
});
$('.add').click(function() {
var count = $("input").length;
count++;
var row = $("<div>", {
class: "flex-row"
}).insertBefore(this);
$("<label>").appendTo(row);
$("<input>", {
type: "text",
class: "input",
id: "custom-text-" + count,
placeholder: "custom text " + count,
tabindex: count
}).appendTo($("label", row));
$("<button>", {
class: "remove"
}).html("-").appendTo(row);
$("<span>", {
class: "output",
dataid: "custom-text-" + count
}).insertAfter($("#custom_wrapper .output:last"));
});
$('body').on('click', '.remove', function() {
$(this).parent('.flex-row').remove();
var j = $(this).parent().find('.input').attr("id");
$('#custom_wrapper .output[dataid="' + j + '"').empty();
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<div class="container">
<div class="wrapper">
<article>
<section>
<div class="flex-row">
<label
><input
class="input"
type="text"
name=""
id="custom-text-1"
placeholder="custom text"
tabindex="1" /></label
><button class="remove">-</button>
</div>
<div class="flex-row">
<label
><input
class="input"
type="text"
name=""
id="custom-text-2"
placeholder="custom text 2"
tabindex="2" /></label
><button class="remove">-</button>
</div>
<button class="add">+</button>
<div class="flex-row">
<div class="token">
{{customText[<span id="custom_wrapper"><span class="output" dataid="custom-text-1"></span><span class="output" dataid="custom-text-2"></span></span>]}}
</div>
</div>
</section>
</article>
</div>
</div>
I also tried to add the pipe with css instead, the part that changes in the jquery is the following:
$(".container").on('input', 'input[type=text]', function(event) {
var i = $(this).closest(".flex-row").index();
v=$(this).val();
$("#custom_wrapper .output").eq(i).html(v);
});
I reformulated my delete function to delete instead of emptying
$('body').on('click', '.remove', function() {
const i = $(this).closest(".flex-row").index();
$("#custom_wrapper .output").eq(i).remove();
$(this).parent('.flex-row').remove();
})
Final code looks like this :
<html><head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<script>
$(function() {
$(".container").on('input', 'input[type=text]', function(event) {
var i = $(this).closest(".flex-row").index();
// var v = (i == 0) ? $(this).val() : "|" + $(this).val();
v=$(this).val();
$("#custom_wrapper .output").eq(i).html(v);
});
$('.add').click(function() {
var count = $("input").length;
count++;
var row = $("<div>", {
class: "flex-row"
}).insertBefore(this);
$("<label>").appendTo(row);
$("<input>", {
type: "text",
class: "input",
placeholder: "custom text " + count,
tabindex: count
}).appendTo($("label", row));
$("<button>", {
class: "remove"
}).html("-").appendTo(row);
$("<span>", {
class: "output"
}).appendTo($("#custom_wrapper"));
});
$('body').on('click', '.remove', function() {
const i = $(this).closest(".flex-row").index();
$("#custom_wrapper .output").eq(i).remove();
$(this).parent('.flex-row').remove();
})
});
</script>
<style>
.output:not(:first-child):before{
content:'|';
}
</style>
</head>
<body>
<div class="container">
<div class="wrapper">
<article>
<section>
<div class="flex-row">
<label for="custom-text-1"><span class="visually-hidden">Custom Text 1</span><input class="input" type="text" id="custom-text-1" placeholder="custom text" tabindex="1" /></label><button class="remove">-</button>
</div>
<div class="flex-row">
<label for="custom-text-2"><span class="visually-hidden">Custom Text 2</span><input class="input" type="text" id="custom-text-2" placeholder="custom text 2" tabindex="2"></label><button class="remove">-</button>
</div>
<button class="add">+</button>
<div class="flex-row">
<div>customText{{[<span id="custom_wrapper"><span class="output"></span><span class="output"></span></span>]}}</div>
</div>
</section>
</article>
</div>
</div>
</body>
It works, but this solution doesn’t suit me: I use a copy function to copy and paste the exit code, and when I copy and paste, the separators are not there, because they are added as pseudo-elements, and seem not to be present in the DOM.
So I definitely need a jquery/javascript solution that actually adds these pipes…
2
Answers
Might make more sense, if you rebuilt the output completely every time:
– loop over all the input fields, get their value wrapped into a span – and then finally join the whole array together with a pipe symbol. (And the CSS that added it as a pseudo element, needs to be removed.)
And your function that removes a field, needs to trigger the input event on the first field left, to update the output – or simply clear the wrapper content, if there are no fields left:
I think what you’re trying achieve can simply be done by using CSS only.