Function to split full name into first & last In angular, I have an input field for a user's full name. And a function called splitName which extracts the first / last name from the field. Is there a way to improve this logic?

&lt;input type="text" name="fullName" ng-model="data.full_name" /&gt;


On the backend, on form submit I do a POST which requires both a first_name and last_name in the body.

    scope.splitName = function(data, fullName) {
      var formData = angular.copy(data),
          nameArr,
          _lastName;

      if (fullName) {
        nameArr = fullName.split(' ');

        if (nameArr.length &gt; 2) {
          _lastName = nameArr.pop();
          formData.first_name = nameArr.join(' ');
          formData.last_name = _lastName;
        } else {
          formData.first_name = nameArr[0];
          formData.last_name = nameArr[nameArr.length - 1];
        }
      }

      // remove full name as its not needed for backend
      delete formData.full_name;

      // return the copy
      return formData;
    };


Therefore, these are some examples.

scope.data = { 
   full_name: 'Joe Middle Name Smith',
   first_name: '',
   last_name: '',
}

var example = scope.splitName(scope.data, scope.data.full_name);

//- which should return
{ 
  first_name: 'Joe Middle Name',
  last_name: 'Smith'
}
First of all, you should be aware that "first name" and "last name" are very tricky concepts. An example in that linked Wikipedia article is José Luis Rodríguez Zapatero. José Luis is the first name, though it's in two words. Rodríguez Zapatero are both surnames (paternal and maternal). Or you have cultures where "name" means surname first and then given name, i.e. the opposite of Western tradition. Example in the linked article is Zhang Wei, Zhang being the family name and Wei being the given name.

Heck, royalty and aristocracy don't even have regular surnames, really (or they're almost never used). They're just "of" some place; Elizabeth II of England, for example. Or take someone like Albert Maria Lamoral Miguel Johannes Gabriel, 12th Prince of Thurn and Taxis (yes, that's the guy's full "name" though it's part-title and honorific). Rarely something you need to worry about of course, but just to show that names aren't simple.

Hence the most common - and most robust - solution is to simply use two text fields: First name and last name. Trying to split things in code is nigh impossible because there's no single, standard naming scheme for everyone, everywhere.

Even Facebook, which certainly has the brains and computing power to attempt something clever, just uses two separate input fields. It's just easier.

So short answer: Don't try. Just make two inputs. Especially as the backend needs two separate values anyway.

But hey, code review:


I don't see the need to pass in the fullName separately. It's already in the data object.
I'm not sure why _lastName has an underscore in it. There's (as far as I can tell) nothing special about that variable.
I'm also not sure why it's there to begin with. You can just assign to formData.last_name directly; no need to to store it in a local variable first.
There's no need for the if (nameArr.length &gt; 2) branching. Given an array of exactly two words, the first branch would do the same as the else branch does, just via a different route. So, really, the pop and join strategy covers both cases already.
... what it doesn't cover is the case where there's only 1 word. If fullName is just "John", then that will (via the else branch) become formData.first_name. But formData.last_name will just undefined. If you only use the pop and join strategy, you'd get "John" as the last name, and empty string as the first name. Either way, it's not optimal.
When you split, you'll split twice on double whitespace and split on leading/trailing whitespace, too. So given a full name like " John  Smith ", you get nameArr = ["", "John", "", "Smith", ""].
I believe Angular can/will automatically trim leading/trailing whitespace, though. If not, you can use String.trim. However, doubled whitespace will remain, so split with a regular expression like /\s+/ instead.


I'd do this:

var nameArr = formData.full_name.split(/\s+/);
formData.first_name = nameArr.slice(0, -1).join(" ");
formData.last_name = nameArr.pop();


That's pretty much it. You'll still want to copy the formData, and perhaps delete the full_name property, but otherwise that's the meat of it. It'll still be weird if full_name is just "John", because you'd get "John" as both first and last name, so you should probably have some more validation somewhere.

Still, though: Just use two fields.