Jerad Rose
Jerad Rose

Reputation: 15513

Where does formatting logic belong with MVC?

Say my phone number is stored in the database as a 10-digit string:

0000000000

And I want to format this phone number when presenting it to the user as:

(000) 000-0000

And I have an extension method in a utility assembly that handles this formatting:

static string ToPhoneNumber(this string value)
{
    return Regex.Replace(value, @"(\d{3})(\d{3})(\d{4})", "($1) $2-$3");
}

My question is, at what point do I apply this conversion?

1) In the view:

@Model.PhoneNumber.ToPhoneNumber()

2) In the view model:

public string FormattedPhoneNumber
{
    get
    {
        return this.PhoneNumber.ToPhoneNumber()
    }
}

3) In the controller:

userModel.FormattedPhoneNumber = userModel.PhoneNumber.ToPhoneNumber()

4) In the domain model (same implementation as #2)

5) In the service (same implementation as #3)

Also, does the answer depend whether it's a global formatting need (like phone number) vs. an isolated one-time formatting on a single view?

I would give my thoughts, but don't want to influence any answers.

Upvotes: 8

Views: 2656

Answers (7)

Patrick Huber
Patrick Huber

Reputation: 756

I would argue that this is modeling, not formatting. If the receiving application needs to re-format the order, spacing or capitalization of these fields it must first split the single field into several separate fields.

This should be the responsibility of the Services layer. We are talking schema, not format. The application requires that the fields be split as part of its data contract. Where this split happens should be in the Application Services layer that your app consumes.

The services layer should try to add metadata to the information through schema.

For example, if I receive a phone number from a data contract like this: 1234567890

The requriements for presentation are as follows: (123) 456 – 7890

The services tier should be breaking the phone number apart into its elements

<PhoneNumber>
<CountryCode>1</CountryCode>
<Area>123</Area>
<Prefix>456</Prefix>
<LineNumber>7890</LineNumber>
</PhoneNumber>

Upvotes: 0

JerKimball
JerKimball

Reputation: 16934

First off, with architectural patterns in general, and especially those dealing with "separation of concerns", the final arbiter is always "what is the best approach in my scenario" - I strongly believe that dogmatic adherence to a set of rules without considering your own plans and needs is a horrible practice. Not to mention the fact there is no clear consensus here: depending on your variety of XYZ (MVC, MVP, MVVM) you'll find opposing thoughts on what goes where all over the internets.

That said, my quick-twitch answer to the question is "Use your judgement".

Arguments for "in the view":

  • it deals with presentation, therefore it is the views responsibility

Arguments for "in the view model":

  • generally, the role of the view model is to provide "ready to data bind" representations of the model - hence, transforming model data into a form directly consumable by the view is the responsibility of the view model

Arguments for the model:

  • this could be an excessively common representation for the model data; therefore, following DRY, the model will assume responsibility for this representation

Arguments for the controller:

  • ... Ok, can't think of a reasonable one here. Controllers typically respond to actions, so it's a stretch to justify it belonging here.

The point I'm trying to make is that so long as a single point of your system accepts and takes on the responsibility and that responsibility is handled solely by that component/layer/class, you've accomplished the primary goal, which is to prevent dilution/repetition/low cohesion.

My personal opinion, fwiw, would probably fall on the view or view model. If this were WPF I'd almost certainly say the view (via the format providers available to wpf data binding). In the web world, I'd probably lean towards the view, although a strong argument for the model exists - say you now want to expose this data via a REST/JSON/etc service: you can easily handle this change (assuming you want to return the formatted data, that is)

TL/DR: It really depends; follow common sense and use your judgement. Just keeping all the related logic in a single place is the important part, and question any dogmatic/commandment-style "Thou Shalt" statements.

Upvotes: 2

Abbas
Abbas

Reputation: 14432

I would place this in the viewmodel and not in the view. The view is intended to just present the data/information to the end-user. Keeping up the separation of concerns makes sure every object is as independent as possible. If you pass the formatted numbers to the view, the view has no concerns about what is to be displayed, just display the formatted numbers.

Upvotes: 0

Rudi Visser
Rudi Visser

Reputation: 21989

It depends on a few things your definition of ViewModel, are you following a (self-coined) MVCVM* approach, where you'd have a ViewModel specific to your view in addition to your domain models?

If so, the VM could certainly contain the formatting logic, that is the whole point of having this View Model in the first place, to Model the View. So Option 2.

That said, the reasoning behind this is that formatting yourself would begin to the DRY principle if you were formatting like this:

@Regex.Replace(Model.PhoneNumber, @"(\d{3})(\d{3})(\d{4})", "($1) $2-$3");

Since you've got an extension method, it's not that much of a problem to call the formatter in your view at all, but I'd still prefer to do it in the dedicated VM.

If your VM is really just the domain model that contains the raw data (see this, pattern 1) then it should definitely be in your View, so Option 1. Just a note, that if you're using this pattern I'd suggest against it as it's making your view strongly coupled against a low-level object, you're better abstracting this out into what you need ensuring that your couplings between Domain Model + View Model are actually strong (ie. compiled at compile time, not runtime!).

Above all - This should certainly not go into your domain model.

* Model, View, Controller, ViewModel. Where the ViewModel contains the data that is to be consumed in your View, in the format of which it requires.

Upvotes: 0

Khalid Abuhakmeh
Khalid Abuhakmeh

Reputation: 10839

I personally like to keep things in my ViewModel because what you end up with is strange looking code in your view if you don't. Let's take your example.

Razor View:

@using MyNamespace.Models.Extensions
@model MyNamespace.Models.ViewModels.IndexViewModel

@if (string.IsNullOrWhiteSpace(Model.PhoneNumber) {
   <div> @Model.PhoneNumber.ToPhoneNumber() </div>  
}

Versus the alternative:

Razor View:

@model MyNamespace.Models.ViewModels.IndexViewModel

@Model.FormattedPhoneNumber

ViewModel :

 public string FormattedPhoneNumber {
     get {
         return PhoneNumber.IsEmpty()
         ? "Not Available"
         : PhoneNumber.ToPhoneNumber();
     }
 }

You could definitely improve my code, but the point is that it keeps your views simpler and lest cluttered with branching logic.

Also, I never claimed to be a saint, so I don't always follow my own advice, but I should. Do as I say, not as I do :)

Upvotes: 5

Carlos Grappa
Carlos Grappa

Reputation: 2381

Option 1 is the best, followed by 2. In the controller, you should actually remove the formatting to send it to the service layer, so neither the domain model nor the service model are aware of the formatting.

Upvotes: -1

kos
kos

Reputation: 1387

I think it is view responsibility to decide how to display data. Because only the view knows what is available for presentation. On the other hand it is probably easier to do it in controller. And controller would know about locale of the user. Over all I think it makes very little difference.

Upvotes: 4

Related Questions