196

This feels like it should be simple, so sorry if I'm missing something here, but I'm trying to find a simple way to concatenate only non-null or non-empty strings.

I have several distinct address fields:

var address;
var city;
var state;
var zip;

The values for these get set based on some form fields in the page and some other js code.

I want to output the full address in a div, delimited by comma + space, so something like this:

$("#addressDiv").append(address + ", " + city + ", " + state + ", " + zip);

Problem is, one or all of these fields could be null/empty.

Is there any simple way to join all of the non-empty fields in this group of fields, without doing a check of the length of each individually before adding it to the string?

Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
froadie
  • 79,995
  • 75
  • 166
  • 235

8 Answers8

437

Consider

var address = "foo";
var city;
var state = "bar";
var zip;

text = [address, city, state, zip].filter(Boolean).join(", ");
console.log(text)

.filter(Boolean) (which is the same as .filter(x => x)) removes all "falsy" values (nulls, undefineds, empty strings etc). If your definition of "empty" is different, then you'll have to provide it, for example:

 [...].filter(x => typeof x === 'string' && x.length > 0)

will only keep non-empty strings in the list.

--

(obsolete jquery answer)

var address = "foo";
var city;
var state = "bar";
var zip;

text = $.grep([address, city, state, zip], Boolean).join(", "); // foo, bar
georg
  • 211,518
  • 52
  • 313
  • 390
131

Yet another one-line solution, which doesn't require jQuery:

var address = "foo";
var city;
var state = "bar";
var zip;

text = [address, city, state, zip].filter(function(val) {
  return val;
}).join(', ');

console.log(text);
Lee Taylor
  • 7,761
  • 16
  • 33
  • 49
aga
  • 27,954
  • 13
  • 86
  • 121
  • 48
    This is probably the best answer. Uses native functions. If you're using es6/es2015 it can be shortened to just `[address, city, state, zip].filter(val => val).join(', ')` – Sir.Nathan Stassen Oct 31 '16 at 14:55
16

Lodash solution: _.filter([address, city, state, zip]).join()

Tim Santeford
  • 27,385
  • 16
  • 74
  • 101
5

@aga's solution is great, but it doesn't work in older browsers like IE8 due to the lack of Array.prototype.filter() in their JavaScript engines.

For those who are interested in an efficient solution working in a wide range of browsers (including IE 5.5 - 8) and which doesn't require jQuery, see below:

var join = function (separator /*, strings */) {
    // Do not use:
    //      var args = Array.prototype.slice.call(arguments, 1);
    // since it prevents optimizations in JavaScript engines (V8 for example).
    // (See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments)
    // So we construct a new array by iterating through the arguments object
    var argsLength = arguments.length,
        strings = [];

    // Iterate through the arguments object skipping separator arg
    for (var i = 1, j = 0; i < argsLength; ++i) {
        var arg = arguments[i];

        // Filter undefineds, nulls, empty strings, 0s
        if (arg) {
            strings[j++] = arg;
        }
    }

    return strings.join(separator);
};

It includes some performance optimizations described on MDN here.

And here is a usage example:

var fullAddress = join(', ', address, city, state, zip);
Community
  • 1
  • 1
Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
3

Try

function joinIfPresent(){
    return $.map(arguments, function(val){
        return val && val.length > 0 ? val : undefined;
    }).join(', ')
}
$("#addressDiv").append(joinIfPresent(address, city, state, zip));

Demo: Fiddle

Arun P Johny
  • 384,651
  • 66
  • 527
  • 531
0
$.each([address,city,state,zip], 
    function(i,v) { 
        if(v){
             var s = (i>0 ? ", ":"") + v;
             $("#addressDiv").append(s);
        } 
    }
);`
nicb
  • 191
  • 2
  • 10
0

Here's a simple, IE6 (and potentially earlier) backwards-compatible solution without filter.

TL;DR → look at the 3rd-last block of code

toString() has a habit of turning arrays into CSV and ignore everything that is not a string, so why not take advantage of that?

["foo", null, "bar", undefined, "baz"].toString()

foo,,bar,,baz

This is a really handy solution for straightforward CSV data export use cases, as column count is kept intact.


join() has the same habit but let's you choose the joining delimiter:

['We built', null, 'this city', undefined, 'on you-know-what'].join('  ')

We built this city on you-know-what


As the OP asking for a nice space after the comma and probably don't like the extra commas, they're in for a replace-RegEx treat at the end:

["foo", null, "bar", undefined, "baz"].join(', ').replace(/(, ){2,}/g, ', ')

foo, bar, baz

Caveat: (, ){2,} is a rather simple RegEx matching all 2+ occurrences of commas followed by a space – it therefore has the potentially unwanted side-effect of filtering any occurrences of , , or , at the start or end of your data.

Of that is no concern, you're done here with a neat and simple, backwards-compatible one-liner.

If that is a concern, we need come up with a delimiter that is so far-out that the probability of it appearing twice in your data items (or once at the beginning or the end) approaches zero. What do you think about, for instance, crazy-ſđ½ł⅞⅝⅜¤Ħ&Ł-delimiter?

You could also use literally any character, probably even ones that don't exist in your local charset, as it is just a stop-signifier for our algorithm, so you could do:

["foo", null, "bar", undefined, "baz"]
  .join('emoji-✊-delimiter')
  .replace(/(emoji-✊-delimiter){2,}/g, ', ')

or (in a more DRY version of this:

var delimiter = 'emoji-✊-delimiter'
var regEx = new RegExp('(' + delimiter + '){2,}', 'g')

["foo", null, "bar", undefined, "baz"].join(delimiter).replace(regex, ', ')
Philzen
  • 3,945
  • 30
  • 46
-1

2023 answer

A simpler solution using ternary operator

let append = `${address || ''}, ${city || ''}, ${state || ''}, ${zip || ''}`;

$("#addressDiv").append(append); 

It will evalutate if the var is no falsy. If it is, will return an empty string.

Dudo1985
  • 177
  • 2
  • 3
  • 12