5

My first SO question! Here's what I am trying to do:

I'm rewriting a tool that generates some code a user can paste directly into Craigslist and other classified ad posting websites. I have created a list of websites (they populate from a database with PHP) the user can choose from with a radio button, and I want their choice to populate as bare text (not a link) between some <p></p> elements in a textarea. I'm using jQuery for this.

Textarea before the user chooses:

    <p id="thing"></p>

Textarea after the user chooses:

    <p id="thing">www.somewebsite.com</p>

HTML

<input type="radio" name="sitechoice" value="www.websiteone.com">www.websiteone.com<br />
<input type="radio" name="sitechoice" value="www.secondwebs.com">www.secondwebs.com

<textarea>
 Some stuff already in here
 Here is the website you chose:
 <p id="thing"></p>
 More stuff already here.
</textarea>

JS

$(document).ready(function () {
    $("input").change(function () {
        var website = $(this).val();
        alert(website);
        $("#thing2").html(website);
    });
});

JS Fiddle (With comments)

If you see the JS Fiddle, you can see that I put another p element on the page outside the textarea, and it updates just fine, but the one inside the textarea does not. I have read many other like questions on SO and I'm starting to think that I can't change an element that's between textarea tags, I can only change the entire textarea itself. Please, lead me to enlightenment!

flanger001
  • 757
  • 6
  • 16
  • 9
    Your "p element" inside the textarea is not an element, it's just plain text. Textarea can't have HTML. – Teemu Dec 06 '13 at 17:44
  • i guess that the comment above it's the answer :) – kawashita86 Dec 06 '13 at 17:44
  • Refer to this question: http://stackoverflow.com/questions/10585029/parse-a-html-string-with-js – Prashant Borde Dec 06 '13 at 17:51
  • @Teemu - that doesn't mean that he can't alter the value, though . . . just that he can't do it using only DOM manipulation. – talemyn Dec 06 '13 at 17:57
  • @Teemu You _can_ treat it as an HTML element though, if you pull it out and wrap it in jQuery's `$()`, or use plain JS like in the link @PrashantBorde provided. – justisb Dec 06 '13 at 18:04
  • @talemyn , jblasco You're right, but I only have pointed out, why OP's code is not working. I've never said that he can't do this... – Teemu Dec 06 '13 at 18:05
  • @Teemu Thanks! I did not realize that it wouldn't be considered an element because it's between textarea tags. That is very helpful! – flanger001 Dec 06 '13 at 18:31
  • @flanger001 Actually I should have posted you a link to a MDN document a long time ago : ). Here it is: [` – Teemu Dec 06 '13 at 18:41

4 Answers4

4

You actually can fairly easily manipulate the text contents of the textarea like it is part of the DOM, by transforming its contents into a jQuery object.

Here is a jsFiddle demonstrating this solution: http://jsfiddle.net/YxtH4/2/

The relevant code, inside the input change event:

// Your normal code
var website = $(this).val();
$("#thing2").html(website);

// This turns the textarea's val into a jQuery object ...
// And inserts it into an empty div that is created
var textareaHtml = $('<div>' + $("#textarea").val() + '</div>');
// Here you can do your normal selectors
textareaHtml.find("#thing").html(website);
// And this sets the textarea's content to the empty div's content
$("#textarea").val(textareaHtml.html());

The empty div wrapping your HTML is so that you can easily retrieve it as a string later using jQuery's .html() method, and so the parse does not fail if additional text is entered around the p element inside the textarea.

The real magic is $($("#textarea").val()), which takes your textarea's text and parses it into an HTML node contained in a jQuery object.

justisb
  • 7,081
  • 2
  • 26
  • 44
  • I tried your fiddle and it worked great so long as there wasn't text around the `

    ` anywhere, but when I added text around it, it stopped working (on the fiddle). But, regardless, I really like how you approached this.

    – flanger001 Dec 06 '13 at 19:11
  • While I definitely agree that being aware that you can create DOM from strings using `$(STRING_VAL)` is great to know, does this not seem like overkill, when you can simply get the value of the textarea, update it, and then set it again? – talemyn Dec 06 '13 at 19:17
  • @talemyn I had assumed his question was just an example and that he was planning on doing something more complicated later, where this would seem less like overkill. – justisb Dec 06 '13 at 21:01
  • @flanger001 Ah, it's because the jQuery was throwing an error when the first thing found was text. I updated my answer and the jsFiddle so that it now works, by changing how the `div` wrapper is created. – justisb Dec 06 '13 at 21:05
  • Okay, I see what you did, and it works great. I can see why `$("
    ").append($($("#textarea").val()));` would be problematic compared to `var textareaHtml = $('
    ' + $("#textarea").val() + '
    ');`, and latter looks a lot better anyway. Like I said, I think it's clever that you created an invisible div and then manipulated the div. I think @talemyn's solution is a more direct approach, but both of these are great ways to think about the issue, and I definitely know more now than I did this morning. **EDIT**: Hit return too soon.
    – flanger001 Dec 07 '13 at 01:38
1

It can't do it the way that you are thinking (i.e., manipulate it as if it were a DOM element), but it is still accessible as the value of the textarea, so you can retrieve it like that, use basic string manipulation to alter it, and then set the updated string as the new value of the textarea again.

Something like this . . . first give the <textarea> an id value:

<textarea id="taTarget">
    Some stuff already in here
    Here is the website you chose:
    <p id="thing"></p>
    More stuff already here.
</textarea>

Then alter your script like this:

$(document).ready(function () {
    $("input").change(function () {
        var website = $(this).val();

        var currentTAVal = $("#taTarget").val();
        $("#taTarget").val(currentTAVal.replace(/(<p id="thing">)([^<]*)(<\/p>)/, "$1" + website  + "$3"));
    });
});

Unless you need the <p> element in there, you might consider using a more simple placeholder, since it won't actually act as an HTML element within the textarea. :)

EDIT : Fixed a typo in the .replace() regex.

talemyn
  • 7,822
  • 4
  • 31
  • 52
  • This worked beautifully, thank you very much! The regex is exactly what I needed and is a pretty elegant solution. One question I had was what are the `"$1"` and `"$3"` at the end of the `replace()` method? I understand everything else except those. – flanger001 Dec 06 '13 at 18:53
  • You should only use a single `var` per scope btw. Helps prevent bugs with hoisting and overall is cleaner too. – tibbon Dec 06 '13 at 18:54
  • No problem . . . glad it worked out for you. :) The `"$1"` and `"$3"` are markers that indicate the captured groups in the regex. In this case, there were three captured groups in the pattern that I used . . . `(

    )` and `(<\/p>)` were the first and third (hence, `"$1"` and `"$3"`). If you wanted to use `([^<]*)` for something, that would be denoted by `"$2"`.

    – talemyn Dec 06 '13 at 18:58
  • @tibbon - Meh . . . the "single vs multiple `var`" thing really is personal preference, as long as you aren't careless with your code. Personally, I like to separate them for readability, and to avoid declaring variables that might never get used (based on `if` logic, for example). Lot's of discussion about this: http://stackoverflow.com/questions/810313/what-is-the-reason-behind-jslint-saying-there-are-too-many-var-statements , http://stackoverflow.com/search?q=one+var+vs+multiple+javascript , and http://benalman.com/news/2012/05/multiple-var-statements-javascript/ , for example. – talemyn Dec 06 '13 at 19:13
1

I know that this answer is a little bit late, but here it goes =)

You can do exactly the way you want to do. But for that, you need to implement a small trick.

by having this HTML

<input type="radio" name="sitechoice" value="www.websiteone.com">www.websiteone.com
<br />
<input type="radio" name="sitechoice" value="www.secondwebs.com">www.secondwebs.com
<p id="thing2"></p>
<textarea id="textarea">
<p id="thing"></p>
</textarea>

you can edit textarea content, as a DOM by implementing something like the function changeInnerText

$(document).ready(function () {
    $("input").change(function () {
        var website = $(this).val(); // Gets value of input
        changeInnerText(website);
        //$("#thing").html(website); // Changes
        //$("#thing2").html(website); // Does not change
    });

    var changeInnerText = function(text) {
        var v = $("#textarea").val();
        var span = $("<span>");
        span.html(v);
        var obj = span.find("#thing")[0];
        $(obj).html(text);

        console.log(obj);        
        console.log(span.html());

        $("#textarea").val(span.html());
    }
});

As you can see, I just get the information from the textarea, I create a temporary variable span to place textarea's content. and then manipulate it as DOM.

  • 1
    This is almost exactly the implementation I went with. This is a super old question back from my early days! – flanger001 Sep 08 '15 at 15:25
0

Instead of attempting to insert the text into the <p> element, insert the text into <textarea> element and include the <p> tag. Something like this should do the trick:

Change:

$("#thing").html(website);

to:

$("textarea").html('<p id="thing">'+website+'</p>');

And here is a fiddle: http://jsfiddle.net/nR94s/

Dryden Long
  • 10,072
  • 2
  • 35
  • 47