En este blog post les estaré demostrándoles como utilizar Vue js con ASP.NET Core MVC.
Estaremos utilizando asp.net core con la arquitectura MVC y creando instancias de Vue JS en las pantallas que nos haga falta. También veremos lo básico de Vue JS como condiciones y data binding.
Comenzando
Así que para comenzar creamos un nuevo proyecto en visual studio. Sera un Asp.Net Core Web Application.
En este post estaré utilizando dotnet 5.
Como probablemente ya sabes la arquitectura MVC utiliza modelos, views y controllers para separar responsabilidades. Nos estaremos enfocando en los views y controllers ya que no tenemos una base de datos y estaremos utilizando data dummy de listas en memoria.
Ahora que tenemos nuestra simple aplicación creada vamos a importar el CDN de Vue Js para poder comenzar a utilizarlo.
Vue JS CDN
Vue JS tiene muy Buena documentación, en el área de instalación en los documentos oficiales podemos conseguir el CDN oficial.
Documentación oficial de vue js
Al momento de este tutorial estaré utilizando la versión 2.6.12 de Vue Js.
Vamos a poner nuestro link del CDN en el archivo llamado_Index.cshtml
en el directorio llamado Views > Home.
Lo que hice fue ponerlo abajo del html que trae la pagina por defecto. No lo instale por NPM ya que esto requiere pasos adicionales.
@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
<div id="app">
<h1 class="display-4">{{message}}</h1>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"></script>
Ahora si hacemos debug a nuestro proyecto podremos ver en el Network Tab de nuestro buscador web que el script de Vue Js está siendo utilizado.
Utilizando Vue Js
Ahora podemos comenzar a utilizar Vue Js en nuestro Index.cshtml.
Ahora vamos a crear otro script tag y en el escribiremos una nueva instancia de Vue.
<script>
let app = new Vue({
el: '#app',
data: {
message: `Vue in the works!`
}
})
</script>
Luego en nuestro HTML podemos utilizar el mensaje en nuestra instancia de Vue. Como puedes ver escribimos el mensaje en el HTML utilizando brackets alrededor de la palabra. Esto es porque Vue utiliza “template syntax” para enlazar la data de nuestra instancia y utilizarla de forma simple en el HTML.
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
<div id="app">
<h1 class="display-4">{{message}}</h1>
</div>
</div>
Ahora si hacemos debug de nuestro proyecto podremos ver nuestro mensaje.
Utilizando data del servidor
Vamos a utilizar un ViewModel
en el cual crearemos records (son como clases) y lo devolveremos a nuestro Index.cshtml
y cuando esto sea devuelto lo utilizaremos en Vue.
Así que en el folder de Models vamos a crear una clase llamada IndexViewModel.cs
.
Ahora vamos a crear dos records uno representara un usuario y el otro será el IndexViewModel el cual devolveremos a nuestro View.
public record User
{
public string Username { get; set; }
public string Name { get; set; }
public string LastName { get; set; }
}
public record IndexViewModel
{
public User User { get; set; }
public List<User> FriendList { get; set; }
}
Ahora creamos un nuevo usuario para nuestro ViewModel y lo devolvemos.
public IActionResult Index()
{
var model = new IndexViewModel
{
User = new User
{
LastName = "Rivera",
Name = "Genesis",
Username = "genesisrrios"
}
};
return View(model);
}
Antes de comenzar a utilizar nuestro ViewModel debemos añadir al principio de nuestro Index.cshtml
la siguiente línea: @model IndexViewModel;
Ahora en la instancia de vue vamos a utilizar el modelo para ensenar la data. Para utilizar la data de nuestro modelo en vue hice un Nuevo objeto de usuario y le añadí tres propiedades de nuestro view model.
let app = new Vue({
el: '#app',
data: {
user: {
user_name: '@Model.User.Username',
last_name: '@Model.User.LastName',
name: '@Model.User.Name'
}
}
})
Para utilizar nuestro objeto del usuario debemos utilizar "dot notation" ósea el nombre del objeto un punto y la propiedad.
<div id="app">
<h1 class="display-4">User: {{user.name}}</h1>
<h2 class="display-4">Last name: {{user.last_name}}</h2>
<h2 class="display-4">Username: {{user.user_name}}</h2>
</div>
Resultado:
Declaraciones condicionales y directivas
Vue Js tiene directivas que son básicamente atributos de HTML que se añaden adentro de elementos en el DOM y todos comienzan con v-
esto indica que son atributos de Vue.
v-if
Por ejemplo si quisiéramos ensenar un elemento solamente si una condición es cierta podríamos utilizar v-if
o v-show
.
Ahora si añadimos en nuestra instancia de Vue una lista de amigos llamada friends_list
y creamos unos elementos de HTML nuevos con la siguiente condición v-if=”friends_list.length > 0”
esto solamente será presentado si la lista no esta vacía.
Javascript
data: {
user: {
user_name: '@Model.User.Username',
last_name: '@Model.User.LastName',
name: '@Model.User.Name'
},
friends_list: []
}
HTML
<div class="row py-lg-5" v-if="friends_list.length > 0">
<div class="col-lg-6 col-md-8 mx-auto">
<p>
</p>
</div>
</div>
v-for
Vamos a volver al controller y vamos a crear una lista de amigos en nuestro View Model para presentar en Index.cshtml
.
Ahora el método de Index se ve así:
public IActionResult Index()
{
var model = new IndexViewModel
{
User = new User
{
LastName = "Rivera",
Name = "Genesis",
Username = "genesisrrios"
},
FriendList = new List<User>
{
new User
{
LastName = "Ford",
Name = "Henry",
Username = "henryford121"
},
new User
{
LastName = "Montgo",
Name = "Suzzie",
Username = "mongosus"
},
new User
{
LastName = "Rivera",
Name = "Luis",
Username = "starraiden"
}
}
};
return View(model);
}
Para utilizar nuestra lista vamos a a serializarla (Convertirla a Json) y luego de serializarla (Convertirla a objetos de javascript)
data: {
user: {
user_name: '@Model.User.Username',
last_name: '@Model.User.LastName',
name: '@Model.User.Name'
},
friends_list: []
},
Mounted
Así que vamos a utilizar algo que se llama mounted en Vue js y es básicamente utilizado para hacer algo después de que se crea nuestra instancia de Vue pero antes de que el usuario la vea. Si quieres conocer más sobre este tema te dejo un buen enlace explicativo aquí.
mounted: function () {
}
Utilizando el mounted voy a traer mi lista del modelo serializarla en la variable friendList
y luego de serializarla y asignarle el valor a friends_list
que es parte de la data reactiva de nuestra instancia.
let app = new Vue({
el: '#app',
data: {
user: {
username: '@Model.User.Username',
lastName: '@Model.User.LastName',
name: '@Model.User.Name'
},
friends_list: []
},
mounted: function () {
let friendList = '@Html.Raw(Json.Serialize(Model.FriendList))';
this.friends_list = JSON.parse(friendList);
}
})
Siempre que estemos haciendo referencia a la data reactiva debemos utilizar la palabra this
y un punto antes del nombre de la propiedad.
Ahora vamos a ensenar la data en nuestro HTML, cambiemos el HTML por lo siguiente:
<div class="text-center">
<div id="app">
<h1 class="display-4">User: {{user.name}}</h1>
<h2 class="display-4">Last name: {{user.lastName}}</h2>
<h2 class="display-4">Username: {{user.username}}</h2>
<hr />
<div v-if="friends_list.length > 0">
<h2 class="display-4">Friends!</h2>
<ul class="list-group list-group-flush" v-for="friend in friends_list">
<li class="list-group-item">User: {{friend.name}}, Last Name {{friend.lastName}}, Username: {{friend.username}}</li>
</ul>
</div>
</div>
</div>
Como puedes ver en la lista estamos utilizando v-for
para iterar por la lista que creamos llamada friends_list
, cuando utilizamos v-for
creamos una variable con el nombre que queramos en mi caso es friend
ósea v-for=”friend in friends_list”
y luego utilizamos esa variable para accesar los valores. Por eso ven friend.username
etc.
Ahora si hacemos debug de nuestro código veremos:
Reactividad
Probablemente ya te distes cuenta que todo lo que hice aquí con Vue lo pudimos haber hecho con razor. La belleza de Vue está en la reactividad y no tener que refrescar la pantalla para ensenar data nueva así que intentémoslo.
Vamos a utilizar el Fetch api para hacer post requests y get requests al servidor.
Ya que no tenemos una base de datos voy a mover nuestra lista de amigos a la data temporera de la sesión en Asp.net core. Esta no es la mejor forma de persistir información pero lo hago para demostrar las cosas de forma simple así que esa parte del código no tiene mucha importancia.
Let’s change our Index to use TempData
.
public IActionResult Index()
{
var friendsList = new List<User>
{
new User
{
LastName = "Ford",
Name = "Henry",
Username = "henryford121"
},
new User
{
LastName = "Montgo",
Name = "Suzzie",
Username = "mongosus"
},
new User
{
LastName = "Rivera",
Name = "Luis",
Username = "starraiden"
}
};
TempData[TempDataFriendsList] = JsonConvert.SerializeObject(friendsList);
var model = new IndexViewModel
{
User = new User
{
LastName = "Rivera",
Name = "Genesis",
Username = "genesisrrios"
},
FriendList = friendsList
};
return View(model);
}
Y vamos a añadir dos métodos nuevos uno que será un post request en el cual añadimos un nuevo amigo a la lista y otro en el cual devolvemos la lista.
[HttpPost]
public bool InsertNewFriendInMemory([FromBody]User friend)
{
if (friend == default || !TempData.ContainsKey(TempDataFriendsList)) return false;
var tempData = TempData[TempDataFriendsList];
var deserializedData = JsonConvert.DeserializeObject<List<User>>((string)tempData);
deserializedData.Add(friend);
TempData[TempDataFriendsList] = JsonConvert.SerializeObject(deserializedData);
return true;
}
public List<User> GetFriendsList()
{
var tempData = TempData[TempDataFriendsList];
TempData.Keep();
var deserializedData = JsonConvert.DeserializeObject<List<User>>((string)tempData);
return deserializedData;
}
Ahora vamos a añadir unos inputs para poder escribir el nombre, apellido y username de nuestros amigos y verlo reflejado en la lista de abajo. Para esto vamos a utilizar ‘two-way data binding’ así que utilizaremos la palabra v-model
<hr />
<h1 class="display-4">Create new friend</h1>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1"></span>
</div>
<input type="text" class="form-control" v-model="new_friend.name" placeholder="Name" aria-label="Name" aria-describedby="basic-addon1">
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1"></span>
</div>
<input type="text" class="form-control" v-model="new_friend.lastName" placeholder="Name" aria-label="Name" aria-describedby="basic-addon1">
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1"></span>
</div>
<input type="text" class="form-control" v-model="new_friend.userName" placeholder="Name" aria-label="Name" aria-describedby="basic-addon1">
</div>
<button type="button" class="btn btn-dark">Add friend</button>
<hr />
En nuestra instancia de Vue vamos a crear otro objeto parecido al que tenemos de user y lo llamaremos new_friend
.
new_friend: {
username: "",
lastName: "",
name: ""
},
Este objeto tendrá los valores que escribimos en nuestros inputs.
Ahora vamos a utilizar fetch api para hacer post de nuestros valores y anadirlos a la lista utilizando el metodo que creamos anteriormente.
Cuando el post request termine y la promesa sea resuelta vamos a utilizar el valor que nos devuelve el servidor y de ser cierto invocamos el método getFriendsList
.
getFriendsList: function () {
let self = this;
fetch('@Url.Action("GetFriendsList", "Home")')
.then(response => response.json())
.then(data => self.friends_list = data);
},
addFriend: function () {
let self = this;
fetch('@Url.Action("InsertNewFriendInMemory", "Home")', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(self.new_friend),
})
.then(response => response.json())
.then(data => {
if (data)
self.getFriendsList();
})
}
Vamos a añadir un método para remover amigos de la lista. Primero, en nuestro HTML cambiemos la lista para poder hacer click en ella e invocar un método llamado removeFriend
al cual le pasaremos los valores del amigo en el cual hicimos click, podemos enviar los valores ya que tenemos acceso al objeto friend
creado en el for loop.
La parte importante de este pedazo de HTML es:
v-on:click="removeFriend(friend.username, friend.lastName, friend.name)"
. Esto invoca el método removeFriend cuando el usuario de click en un amigo de la lista enviándole los parámetros especificados.
HTML
<div v-if="friends_list.length > 0">
<h2 class="display-4">Friends!</h2>
<div class="list-group" v-for="friend in friends_list">
<a v-on:click="removeFriend(friend.username, friend.lastName, friend.name)" class="list-group-item list-group-item-action">
User: {{friend.name}}, Last Name {{friend.lastName}}, Username: {{friend.username}}
</a>
</div>
</div>
Javascript
removeFriend: function (username, lastName, name) {
let self = this;
let deleteParameters = {
username: username,
lastName: lastName,
name: name
};
fetch('@Url.Action("RemoveFriend", "Home")', {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(deleteParameters) //if you do not want to send any addional data, replace the complete JSON.stringify(YOUR_ADDITIONAL_DATA) with null
})
.then(response => response.json())
.then(data => {
if (data)
self.getFriendsList();
})
}
C#
[HttpDelete]
public bool RemoveFriend([FromBody] User friend)
{
if (friend == default || !TempData.ContainsKey(TempDataFriendsList)) return false;
var tempData = TempData[TempDataFriendsList];
var deserializedData = JsonConvert.DeserializeObject<List<User>>((string)tempData);
deserializedData.Remove(friend);
TempData[TempDataFriendsList] = JsonConvert.SerializeObject(deserializedData);
return true;
}
¡Llegaste al final!
Eso es todo por ahora, estas cosas básicas que te explique son lo que puedes utilizar para comenzar a utilizarlo. Vue tiene muchas cosas más que vamos a estar tocando en los próximos blog posts tales como los mixins, componentes y mucho más.