Kirk Ross
Kirk Ross

Reputation: 7153

Javascript str.split at colon char and add line break

I feel a bit dumb here. I'm trying to add a line break after a colon in a string like this:

LOCATION: SOME OTHER WORDS AFTER

I would like it to become

LOCATION:
SOME OTHER WORDS AFTER 

My method, being called from a Vue loop, is this:

handleName(name) {
  if (name.includes(":")) {
    return name.replace(":", ":\n");
  } else {
    return name;
  }
}

// the above simply adds a line in the name var but does not actually render an HTML <br>
// I tried using name.split(':'), but for some reason it splits the sting by individual letters.

Maybe because it's being called from Vue like {{ handleName(location.name) }} I have to handle it differently?

Upvotes: 2

Views: 1333

Answers (5)

Robby Cornelissen
Robby Cornelissen

Reputation: 97282

You need to:

  1. Make sure that you insert an HTML linebreak (<br>) instead of a newline character (\n). Except inside specific tags like <pre>, HTML collapses white-space by default, and the newline will not be rendered as a new line.

  2. Make sure that you pass the result of the replace operation to the renderer as HTML, and not as text. If passed as text, the renderer will replace the less than (<) and greater than (>) symbols in the <br> tags with their equivalent entities (&lt; and &gt;).

In VueJS, you can use the v-html directive for this:

<span v-html="name.replace(/:\s*/g, '<br>')"></span>

(!) Be careful when outputting user-defined content as raw HTML. You might be opening yourself up to XSS (and related) vulnerabilities.

Upvotes: 1

zer00ne
zer00ne

Reputation: 44043

The following demo features a function that will break text after a colon on a given string. This function will render the text in HTML or return the edited text as a string value to used elsewhere.

/** 
 * colonBreak(data, DOM = false)
 =------------------------------=
 * Edit text in a particular format pattern:
 *   Insert a line break after any colon.
 =------------------------------------------=
 * @param {string} data - There are two forms of strings that can be accepted:
 *                        1. a literal string or template literal 
 *                        2. the selector of a DOM element that has the text 
 * @param {boolean} DOM - If undefined it defaults to false 
 *                        true:  data represents the selector of a DOM element
 *                               text of DOM element will be formatted
 *                        false: data is the string to be formatted
 =----------------------------------------------------------------------------=
 * @return {string}       if DOM is false, a formatted string will be returned. 
 *            or 
 *         {undefined}    if DOM is true, undefined will be returned and the DOM 
 *                        element text content will be formatted
 */ 

Explanation

When dealing with the text of DOM elements, HTML formats text by default so that multiple whitespaces and line-breaks are normalized. .innerText property is used so that the whitespaces and line-breaks are preserved (\n is not ignored). .innerText or .textContent can be used to extract the text but it's important to apply .innerText to render the formatted string back into the DOM element.

string = node.innerText;

The heart of this function consists of .split() method witch splits the string by a RegExp delimiter into an array of strings:

string.split(/([\w]+:)\s*/)...

The RegExp delimiter instructions are as follows:

  1. (...) capture the match within the parenthesis and use it as a replacement
  2. [...] match the literal and/or class of each character and/or meta-character
  3. \w meta-character that matches any alphanumeric character (including underscores)
  4. + quantifier indicating match of one or more consecutive instances of the match preceding it
  5. : literal colon
  6. \s meta-character that matches a whitespace
  7. * quantifier as + but matches zero or more

Last method used is .join() which will join all the strings of an array into one complete string by a given delimiter:

let formatted = string.split(/([\w]+:)\s*/).join('\n')

Demo

Details are commented in demo

/* 
There are two examples of input:
  1. A <p> with text (located in HTML window of demo)
  2. A string assigned to the variable dataString (below)
    (NOTE: colonBreak() normalizes spacing as well)
*/
const dataString = `keyX: xXxXxXXxXxXx keyY:yYyYyY YyYyYy keyZ: zZ zZ zZ Zz Zz Zz`;

/* 
See documentation in post about the parameters and return
*/
function colonBreak(data, DOM = false) {
  let node, string;

  // if DOM parameter is true...
  if (DOM) {
    /*
    - Reference the DOM element designated by param data
    - Get the textNode within the DOM element
      (NOTE: .innerText preserves whitespaces)
    - Overwrite textNode with the formatted text
      (NOTE: See post on how text is formatted)
    */
    node = document.querySelector(data);
    string = node.textContent;
    node.innerText = string.split(/([\w]+:)\s*/).join(`\n`);
  } else {
    /*
    ...otherwise just return the formatted text
    (NOTE: See post on how text is formatted)
    */
    return data.split(/([\w]+:)\s*/).join(`\n`);
  }
  return false;
}

console.log(colonBreak(dataString));
colonBreak('p', true);
.as-console-wrapper {
  width: 350px;
  min-height: 100%;
  margin-left: 45%;
}
<p>keyX: xXxXxXXxXxXx keyY:yYyYyY YyYyYy keyZ: zZ zZ zZ Zz Zz Zz</p>

Upvotes: 0

Rob Monhemius
Rob Monhemius

Reputation: 5144

To avoid any confusion. It is fine to use a \n in a string, span or whatever.

BUT this works if you assign it to innerText. If you or whatever you are using uses innerHTML it won't work as expected (see example).

function handleName(string) {
  return string.replace(":", ":\n");
}

let div = document.getElementById('div');
let div2 = document.getElementById('div2')
let name = handleName(div.innerText);
div.innerText = name;
div2.innerHTML = name;
div{
  margin-bottom: 10px;
}
<div id='div'>LOCATION: SOME OTHER WORDS AFTER</div>
<div id='div2'></div>

Upvotes: 0

Kostas Minaidis
Kostas Minaidis

Reputation: 5516

You should use the <br/> tag instead of \n:

handleName(name) {
  if (name.includes(":")) {
    return name.replace(":", ":<br/>");
  } else {
    return name;
  }
}

Example in Vue.JS, using the v-html directive to display String as markup:

<template>
    <span v-html="message"></span>
</template>

<script>
export default {
  name: "App",
  data(){
    return {
      message: "LOCATION: SOME OTHER WORDS AFTER".replace(":",":<br/>")
    }    
  },
};
</script>

Upvotes: 1

Haibrayn Gonz&#225;lez
Haibrayn Gonz&#225;lez

Reputation: 181

Normal line breakes like \n are rendered as a white space in an html. To actually render a line break, you can use a <br> element. Also you don't need to check if the colon exists in the string. You can safely attempt to replace it even if it doesn't exist.

handleName(name) {
    return name.replace(":", ":<br/>");
}

Upvotes: 0

Related Questions