O problema
Para quem trabalha com .Net, é muito comum renderizar suas páginas server-side utilizando o Razor. E, por muito tempo, tivemos o jQuery como aliado quando se era necessário fazer alguma chamada AJAX ou manipular algum DOM. Esta era a stack padrão.
Com a adoção do VueJS, nossa vida melhorou muito. Porém, sempre que quisermos representar o objeto renderizado pelo Razor no projeto Vue, precisamos reescrever todo o objeto usando a sintaxe Js.
Neste post, pretendo mostra um pouco de como eu faço para que os objetos enviados do controller para a view estejam também disponíveis no código Vue de forma automática.
Vamos imaginar que tenhamos a seguinte estrutura:
Person.cs
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
PersonController.cs
public class PersonController : Controller
{
public IActionResult Form()
{
var person = new Person();
return View(person);
}
}
Os inputs do formulário já fazem o bind com os atributos do objeto Vue que vamos criar mais adiante.
Form.cshtml
@model Person
<form asp-route="Save" method="post">
<input asp-for="Id" v-model="Model.Id" />
<input asp-for="Name" v-model="Model.Name" />
<input asp-for="Age" v-model="Model.Age" />
</form>
Para que possamos trabalhar com a classe Person
no projeto Vue, e também para que o bind acima funcione, é necessário rescrever a classe inteira dentro do Vue:
main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
data() {
return {
Model: {
Id: 0,
Name: '',
Age: 0
}
}
},
render: h => h(App),
}).$mount('#app')
Obviamente esta é uma abordagem bem simplista, mas ainda assim, seria necessário rescrever toda a classe Person
de alguma forma, para poder ter acesso como no exemplo abaixo:
//...
methods: {
changeName () {
this.Model.Name = 'New Name'
}
}
//...
Preparando as coisas
Precisamos trabalhar com 3 alterações para que as coisas funcionem de forma automática. Primeiro, criaremos um método que transporte o objeto a ser renderizado para um formato JSON. Aqui, vou assumir que você estará criando uma classe BaseController
para poder utilizar este método em todos os seus controllers.
BaseController.cs
public class BaseController : Controller
{
protected JsonSerializerSettings jsonSettings;
public BaseController()
{
this.jsonSettings = new JsonSerializerSettings
{
Culture = new CultureInfo("pt-BR"),
DateFormatString = "dd/MM/yyyy",
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
Formatting = Formatting.Indented
};
}
public ViewResult ViewJson(object model, string view = "")
{
// Transformamos o objeto em Json e enviamos para a view usando ViewBags
ViewBag.Model = JsonConvert.SerializeObject(model, this.jsonSettings);
// Depois a view é renderizada normalmente
if (string.IsNullOrWhiteSpace(view))
return View(model);
else
return View(view, model);
}
}
Agora com o objeto serializado, vamos adicioná-lo em uma variável JavaScript global chamada model
. Esta variável será utilizada posteriormente em nosso projeto Vue.
Faremos isso no arquivo de Layout, uma vez que esta solução será usada por todo o sistema.
_Layout.cshtml
<html>
<head>
<script>
@if (string.IsNullOrWhiteSpace(ViewBag.Model))
{
<text>const model = null;</text>
}
else
{
<text>const model = @Html.Raw(ViewBag.Model);</text>
}
</script>
</head>
...
</html>
E por último, precisamos vamos tornar a variável global model
acessível a partir do root do Vue.
Main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
data() {
return {
Model: model
}
},
render: h => h(App),
}).$mount('#app')
// Sempre adiciono esta linha para deixar o Vue acessível pelo console do navegador
window.vue = vue;
Aplicando as modificações
Agora, basta alterar os controllers, trocando a chamada do método View()
para ViewJson()
.
PersonController.cs
public class PersonController : Controller
{
public IActionResult Form()
{
var person = new Person();
//Única alteração necessária nos controllers
return ViewJson(person);
}
}
Conclusão
Agora, toda e qualquer action retornará além da página Razor renderizada em server-side, você também terá a sua disposição um objeto Vue representando a classe atribuída em @model
.
Top comments (0)