ASP.NET MVC Calculate value in a table

Asked

Viewed 1,063 times

2

I’m developing a record where I’ll have a table with some additional details that should be entered together with the main register.

But one of the columns of this table is calculated, which is where I’m having trouble making this calculation.

Basically, I need to calculate the field ValorCalculado on the basis of Percentual applied on the ValorPrincipal

And this value should appear as the user enters the Main Value or Percentage field

Yes, I made a very simple example, think about an entry system of products in stock, where the user has read an XML and this note has at least 10 products, and is releasing the percentage of product profit per product and wanting to see what the sale value is as it changes these items. Imagine having to make a request to the server every time you have a percentage changed in the View, so it would be good to make the calculation be in the View as well and not only in the server.

In short, I need the Calculated Value to present the Main Value*Percentage every time I have a change in the Main Value or Percentage

Follow the example code

    public class CadastroController : Controller
    {
        // GET: Cadastro
        public ActionResult Index()
        {
            CadastroViewModel model = new CadastroViewModel();

            model.Detalhes.Add(new CadastroDetalhesViewModel());
            model.Detalhes.Add(new CadastroDetalhesViewModel());
            model.Detalhes.Add(new CadastroDetalhesViewModel());
            model.Detalhes.Add(new CadastroDetalhesViewModel());

            return View(model);
        }

        [HttpPost]
        public ActionResult Index(CadastroViewModel model)
        {
            return View(model);
        }
    }

Model

    public class CadastroViewModel
    {
        public CadastroViewModel()
        {
            Detalhes = new List<CadastroDetalhesViewModel>();
        }

        public int CadastroId { get; set; }

        public DateTime DataInicio { get; set; }

        public DateTime DataFim { get; set; }

        public decimal ValorPrincipal { get; set; }

        public decimal Percentual { get; set; }

        public decimal ValorCalculado { get; set; }

        public List<CadastroDetalhesViewModel> Detalhes { get; set; }
    }

    public class CadastroDetalhesViewModel
    {
        public int CadastroId { get; set; }

        public decimal ValorPrincipal { get; set; }

        public decimal Percentual { get; set; }

        public decimal ValorCalculado { get; set; }

    }

View

@model AspNetMvcCalcularValoresTabela.Models.CadastroViewModel

@{
    ViewBag.Title = "View";
}

<h2>View</h2>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>CadastroViewModel</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.CadastroId, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.CadastroId, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.CadastroId, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.DataInicio, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.DataInicio, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.DataInicio, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.DataFim, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.DataFim, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.DataFim, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.ValorPrincipal, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.ValorPrincipal, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.ValorPrincipal, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Percentual, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Percentual, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Percentual, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.ValorCalculado, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.ValorCalculado, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.ValorCalculado, "", new { @class = "text-danger" })
            </div>
        </div>

        <table>
            <thead>
                <tr>
                    <th></th>
                    <th></th>
                    <th></th>
                </tr>
            </thead>
            <tbody>
                @for (int i = 0; i < Model.Detalhes.Count; i++)
                {
                    <tr>
                        <td>@Html.EditorFor(a => a.Detalhes[i].ValorPrincipal, new { htmlAttributes = new { @class = "form-control" } })</td>
                        <td>@Html.EditorFor(a => a.Detalhes[i].Percentual, new { htmlAttributes = new { @class = "form-control" } })</td>
                        <td>@Html.EditorFor(a => a.Detalhes[i].ValorCalculado, new { htmlAttributes = new { @class = "form-control" } })</td>
                    </tr>
                }
            </tbody>
        </table>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

1 answer

5


If I may, I’ll use foreach for the answer.

Just do the same loop calculation, example:

 <tbody>
  @foreach(var item in Model.Detalhes)
  {
    //Não sei qual a regra que você precisa, então farei uma multiplicação, mas altere para sua encessidade.
    item.ValorCalculado = item.ValorPrincipal * item.ValorCalculado; 

      <tr>
          <td>@Html.EditorFor(a => item.ValorPrincipal, new { htmlAttributes = new { @class = "form-control" } })</td>
          <td>@Html.EditorFor(a => item.Percentual, new { htmlAttributes = new { @class = "form-control" } })</td>
          <td>@Html.EditorFor(a => item.ValorCalculado, new { htmlAttributes = new { @class = "form-control" } })</td>
      </tr>
  }
</tbody>

And from what I can see, you’re sending these values to a controller, I’d advise you to use the Begincollectionitem.

Now, if you want to continue using the for, just follow the same logic:

<tbody>
    @for (int i = 0; i < Model.Detalhes.Count; i++)
    {
        Model.Detalhes[i].ValorCalculado = Model.Detalhes[i].ValorPrincipal * Model.Detalhes[i].Percentual;
        <tr>
            <td>@Html.EditorFor(a => a.Detalhes[i].ValorPrincipal, new { htmlAttributes = new { @class = "form-control" } })</td>
            <td>@Html.EditorFor(a => a.Detalhes[i].Percentual, new { htmlAttributes = new { @class = "form-control" } })</td>
            <td>@Html.EditorFor(a => a.Detalhes[i].ValorCalculado, new { htmlAttributes = new { @class = "form-control" } })</td>
        </tr>
    }
</tbody>

I do not understand why you do the calculation by means of a value typed in View. If the system should generate, it would be better to do this in the server, would be more "safe" the calculation.

Editing

Based on AP comments, I will add an alternative answer in jQuery.

To do what you want, we will use the event .Blur() jQuery to change the value of ValorCalculado where the value of a input is amended in this way:

$('input').blur(function(){

	var valorPrincipal = $(this).parent().parent().find('input[id*="ValorPrincipal"]').first().val();
	var percentual = $(this).parent().parent().find('input[id*="Percentual"]').first().val();
  var valorCalculado = valorPrincipal * percentual;
  
  if(valorCalculado != 0){
    $(this).parent().parent().find('input[id*="ValorCalculado"]').first().val(valorCalculado);
  }else{
  	$(this).parent().parent().find('input[id*="ValorCalculado"]').first().val('');
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
  <tr>Valor Principal</tr>
  <tr> Percentual</tr>
  <tr> Valor Calculado</tr>
  <tbody>
    <tr>
        <td><input id="ValorPrincipal1"/></td>
        <td><input id="Percentual1"/></td>
        <td><input id="ValorCalculado1"/></td>
    </tr>
       <tr>
        <td><input id="ValorPrincipal2"/></td>
        <td><input id="Percentual2"/></td>
        <td><input id="ValorCalculado2"/></td>
    </tr>
       <tr>
        <td><input id="ValorPrincipal3"/></td>
        <td><input id="Percentual3"/></td>
        <td><input id="ValorCalculado3"/></td>
    </tr>
  </tbody>
</table>

Example in Jsfiddle.

Explaining what was done:

The explanation is quite simple. Whenever a input is amended and the focus get out of it, that is to get out of input, the new value of the ValorCalculado for the row in the table. To do this, we need to obtain the Principle and Percentage values of the same row. This line of code does this work:

var valorPrincipal = $(this).parent().parent().find('input[id*="ValorPrincipal"]').first().val();

Where $(this) is the element that input that the user has edited, .parent().parent() is responsible for obtaining the tr of each line,.find('input[id*="ValorPrincipal"]').first().val() is responsible for finding the item containing ValorPrincipal in the id (make sure you have it in the id, or change it to whatever you think best) and get its value. Once this is done, simply replicate to the percentage, make the calculation of returning the value to the input corresponding, as shown in the example.

  • Yes, I made a very simple example, think about a system of entry of products in stock, where the user is launching the percentage of profit of product by product and want to see what the sale value is as you change these items. Imagine having to make a request to the server every time you have a changed percentage in the View, so that’s why I need to calculate it in the View as well and not just on the server.

  • @Pablovargas But if the user will enter the calculated value, it makes no sense to have to calculate it, unless it is validations. Now, if this calculation will be generated automatically in the view just to assist, ok. However, if you need this precise value, the ideal is to make a request to the server for each change yes, even in the view, by ajax or jQuery.

  • @Pablovargas If you care about security, you should not leave any information in the view that cannot be changed. But this goes into other factors. Let me know if the answer doesn’t help you

  • but the ValorCalculado will not be typed by the user, will be an aid field of the calculation of the main value*Percentage.

  • @Pablovargas But being in View it is amenable to change. But as you said, you made a simple example, so I can’t state anything about your code.

  • In short, I need the Calculated Value to present the Main Value*Percentage every time I have a change in the Main Value or Percentage

  • @Pablovargas Well, I did it both ways, just test and tell me if it helps you.

  • does not help, because your example would have to come with the values already informed from the server to the view, what I want is that as the values are being typed, the value is being calculated

  • @Pablovargas So you need something with javascript or jQuery, which is not specified in the question. If you don’t have the answer you’re looking for, tomorrow I’ll change the way you need it.

  • Blz, I’ll be waiting

  • @Pablovargas, see if he’ll see you now.

Show 7 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.