4

I have a select tag with an option tag that has a value of "\n". When that option is selected and I get the value using jQuery, JavaScript seems to be treating it as a string literal and not interpreting it as a linefeed.

I have tried escaping, unesacping, escaping then unescaping, using the jQuery htmlEncoding technique, the jQuery htmlDecoding technique, and even tried concatenating with an empty string. I'm pulling my hair out. This should be so simple.

At least 5 workarounds pop into my head almost imediately with various levels of elegance, but at this point, I'm more interested in why this behavior exists. Is there something simple I'm missing? My real question is "why does JavaScript treat a string of \n one way in one context, but differently in another", not "how do I just get it to work".

Here is the code

Html

<select id="delimiter">
  <option value="\n">New Line</option> <!--This should produce a linefeed-->
  <option value=",">, (Comma)</option>
  <option value=";">; (Semicolon)</option>
  <option value="\t">Tab</option>
</select>
<button  onclick="doit()">
  Check It
</button>

JavaScript

function doit(){
  var delimiter = $("#delimiter").val();

  console.debug("\n"); //produces an actual linefeed character
  console.debug(delimiter); //this produces the string "\n"
}

I have a codepen of it here: https://codepen.io/codysechelski/pen/MoJKMB?editors=1111

Cody
  • 85
  • 3
  • 7
  • 2
    HTML doesn't have escape sequences like `\n` or `\t`. https://codepen.io/tarabyte/pen/RgKZwd?editors=1111 So it is not `javascript` that does it :) – Yury Tarabanko Jun 17 '17 at 12:38
  • But once we get the value of the option in JavaScript, it's just a string right? I would think that it would be the same as var s = '\n'. But that seems not to be the case – Cody Jun 17 '17 at 12:41
  • Yep a string of length 2 consisting of two chars `\ ` and `n` which translated to string literals should be `'\\n'`. Try `console.debug(delimiter.split(''), delimiter === '\\n')` – Yury Tarabanko Jun 17 '17 at 12:44
  • Thanks, that explanation is sort of what I was suspecting, but what is so magical about var s = "/n". To me, it looks like a string contains two chars as well. Yet it produces a single linefeed char. Not trying to be difficult here, I just really want to understand what JS is doing behind the curtains. Does var delimiter = $("#delimiter").val(); produce a string that is somehow different that var s = '\n'. Also, is there any way to convert the string that is currently being returned and translated as "//n" to a linefeed? – Cody Jun 17 '17 at 12:58

3 Answers3

4

replace "\n" in your value by the new line code : "&#13;" In HTML tag attribute you must use HTML character entity for special character.

Kashkain
  • 513
  • 4
  • 11
  • Thanks, that does solve the issue, but it doesn't really give me an explanation. I'm more concerned with why does JavaScript treat a string of \n one way in one context, but differently in another – Cody Jun 17 '17 at 12:32
4

"why does JavaScript treat a string of \n one way in one context, but differently in another"

First you should understand that string literal is not actual string in memory but a part of js syntax to create strings. So escape sequences starting with "\" character signals to js engine to treat next char in different way.

HTML doesn't have this special syntax. So "\" is just "\" and "\n" is "\n". When this string cross html-js boundary via DOM API (which is not a part of js syntax) it remains the "same" two letter string.

By the way there are different ways to encode new line in js that produces the same string in memory

const withEscSequence = '\n'

// es2015
const usingStringTemplate = `
`
// directly from char code
const fromCharCode = String.fromCharCode(10)

// using unicode escape sequence
const unicodeEscSequence = '\u000A'

// using hex escape sequence
const hexEscSequence = '\x0A'


console.log(withEscSequence === usingStringTemplate, withEscSequence === fromCharCode, withEscSequence === unicodeEscSequence, withEscSequence ===  hexEscSequence)
Yury Tarabanko
  • 44,270
  • 9
  • 84
  • 98
2

Why does JavaScript treat a string of \n one way in one context, but differently in another?

Because it's not JavaScript, and not a string literal. <option value="\n"> is plain HTML, and the backslash is not an escape character in HTML. You can use a literal linebreak or a character entity instead.

I have tried escaping…

But apparently not the right one. It always depends on the context which escaping to use, and sometimes you even need to chain them. Some suitable solutions:

  • Literal characters in the HTML source:

    <option value="
    ">New Line</option>
    <option value=",">Comma</option>
    <option value=" ">Tab</option>
    

    selectEl.value
    
  • Character entity references in the HTML source, to avoid the weird formatting:

    <option value="&#x000A;">New Line</option> <!-- or &#10; -->
    <option value=",">Comma</option>
    <option value="&#x0009;">Tab</option> <!-- or &#9; -->
    

    selectEl.value
    
  • JSON literals in the HTML source to avoid knowing charcodes:

    <option value="&quot;\n&quot;">New Line</option>
    <option value="&quot;,&quot;">Comma</option>
    <option value="&quot;\t&quot;">Tab</option>
    

    JSON.parse(selectEl.value)
    
  • JSON string contents in the HTML source:

    <option value="\n">New Line</option>
    <option value=",">Comma</option>
    <option value="\t">Tab</option>
    

    JSON.parse('"'+selectEl.value+'"')
    
Bergi
  • 630,263
  • 148
  • 957
  • 1,375