martes, 19 de octubre de 2010

ASP.NET - Carrito de compras - II

shopping-cart Este post es la continuación de este otro.
Vamos a hacer un resumen del post anterior. Lo que hicimos fue crear tres clases:
  1. Product.- Para capturar cada dato de cada una de los productos disponibles (ID, Nombre, precio).
  2. ProductOfTheShoppingCart.- Para capturar cada dato de cada uno de los productos añadidos al carrito de compras (ID, Nombre, Precio, Cantidad, Subtotal).
  3. ShoppingCart.- Permite gestionar el carrito de compras.
Ahora sí, empecemos con este post. Entonces, vamos a crear la interfaz para poder usar las clases previamente creadas.
Añadan una página llamada WebForm1.aspx y usen este código:
<html>
<head>
<title>Carrito de Compras</title>
<style type="text/css">
*
{
font-family: Trebuchet MS;
}
table
{
width: 100%;
border-collapse: collapse;
}
th
{
background-color: black;
color: white;
text-align: left;
padding: 0px 10px 0px 10px;
}
td
{
border: solid 1px black;
padding: 0px 10px 0px 10px;
background-color: orange;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<fieldset>
<legend>Catálogo de productos</legend>
<asp:Repeater ID="rptProducts" runat="server">
<HeaderTemplate>
<table>
<tr>
<th>
Producto
</th>
<th>
Precio
</th>
<th>
</th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td style="width: 85%">
<%# Eval("ProductName")%>
                    </td>
<td style="white-space: nowrap">
$ <%# Eval("Price")%>
                    </td>
<td>
<asp:Button ID="btnAddToCart" CommandArgument='<%# Eval("ProductID")%>' runat="server" Text="+ Agregar al carrito" />
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
</fieldset>
<p>
&nbsp;</p>
<fieldset>
<legend>Mis productos seleccionados</legend>
<asp:Repeater ID="rptShoppingCart" runat="server">
<HeaderTemplate>
<table>
<tr>
<th>
Producto
</th>
<th>
Precio
</th>
<th>
Cantidad
</th>
<th>
SubTotal
</th>
<th>

</th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td style="width: 70%">
<%# Eval("ProductName")%>
                    </td>
<td style="white-space: nowrap">
$ <%# Eval("Price")%>
                    </td>

<td style="white-space:nowrap">
<asp:TextBox ID="txtQuantity" Text='<%# Eval("Quantity")%>' Width="70px" runat="server"></asp:TextBox>
<asp:Button ID="btnRefresh" CommandArgument='<%# Eval("ProductID")%>' CommandName="Refresh" runat="server" Text="Refrescar" />
</td>                        

<td style="white-space: nowrap">
$ <%# Eval("SubTotal")%>
                    </td>

<td>
<asp:Button ID="btnQuit" CommandArgument='<%# Eval("ProductID")%>' CommandName="Quit" runat="server" Text="- Quitar del carrito" />
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
<tr>
<th colspan="3" style="text-align: right">
Total:
</th>
<td colspan="1" style="white-space: nowrap">
<asp:TextBox ID="txtTotal" runat="server"></asp:TextBox>
</td>
<td></td>
</tr>
</table>
</FooterTemplate>
</asp:Repeater>
</fieldset>
<div style="text-align: center; margin-top: 20px">
<asp:Button ID="btnBuyNow" runat="server" Text="Comprar >>" />
</div>

</form>
</body>
</html>


Desde el lado del código vb.net usen este código:

Public Class WebForm1
Inherits System.Web.UI.Page

Dim AvailableProducts As String = "AvailableProducts"
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If IsPostBack Then Return

'añado productos... usando un constructor y sin usar constructor
'**********************************************
Dim Products As New List(Of Product)
Products.Add(New Product(1, "Product 01", 99.99))
Products.Add(New Product(2, "Product 02", 150.0))
Products.Add(New Product(3, "Product 03", 199.99))

Dim Prod As New Product
Prod.ProductID = 4
Prod.ProductName = "Product 04"
        Prod.Price = 59.99
Products.Add(Prod)

Prod = New Product
Prod.ProductID = 5
Prod.ProductName = "Product 05"
        Prod.Price = 179.89
Products.Add(Prod)

Session(AvailableProducts) = Products

rptProducts.DataSource = Products
rptProducts.DataBind()

End Sub

Protected Sub rptProducts_ItemCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.RepeaterCommandEventArgs) Handles rptProducts.ItemCommand
Dim ProductID As Integer = e.CommandArgument

'primero elimino el elemento del carrito de compras
'**********************************************
ShoppingCart.Remove(ProductID)

'Añado el producto
'**********************************************
Products_Add(ProductID, 1)

'Ordeno... aunque no es necesario
'**********************************************
ShoppingCart.Sort()

rptShoppingCart.DataSource = ShoppingCart.GetAll
rptShoppingCart.DataBind()

End Sub

Protected Sub rptShoppingCart_ItemCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.RepeaterCommandEventArgs) Handles rptShoppingCart.ItemCommand
Dim ProductID As Integer = e.CommandArgument

'QUITAR 
'**********************************************
ShoppingCart.Remove(ProductID)

If e.CommandName = "Refresh" Then
'Cantidad de productos
'**********************************************
Dim txtQuantity As TextBox = DirectCast(e.Item.FindControl("txtQuantity"), TextBox)
Dim Quantity As Integer = 1
If Not IsNothing(txtQuantity) Then Quantity = txtQuantity.Text

'Añado el producto
'**********************************************
Products_Add(ProductID, Quantity)
End If

'Ordeno... aunque no es necesario
'**********************************************
ShoppingCart.Sort()

rptShoppingCart.DataSource = ShoppingCart.GetAll
rptShoppingCart.DataBind()

End Sub

Private Sub Products_Add(ByVal ProductID As Integer, ByVal Quantity As Integer)
'busco en la session(AvailableProducts) los productos disponibles... ud debe buscar en la bd
'**********************************************
If Not IsNothing(Session(AvailableProducts)) Then
Dim Products As New List(Of Product)
Products = Session(AvailableProducts)

Dim P As Product = Products.Find(Function(Prod As Product) Prod.ProductID = ProductID)
If Not IsNothing(P) Then

Dim ProductOfTheSC As New ProductOfTheShoppingCart(P.ProductID, P.ProductName, P.Price, Quantity)
ShoppingCart.Add(ProductOfTheSC)
End If
End If

End Sub

Private Sub rptShoppingCart_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles rptShoppingCart.ItemDataBound
If e.Item.ItemType = ListItemType.Footer Then

'Calculo el TOTAL
'**********************************************
Dim txtTotal As TextBox = DirectCast(e.Item.FindControl("txtTotal"), TextBox)
If Not IsNothing(txtTotal) Then txtTotal.Text = ShoppingCart.Total

End If
End Sub

End Class


Ahora simplemente presionen F5 para ejecutar la página, luego de eso prueben a añadir, quitar o cambiar la cantidad de productos del carrito de compras.

Espero que les sea de utilidad ;)

22 comentarios:

María Florencia dijo...

Hm... Realmente sencillo... A partir de esto, voy a tratar de elazar datos de mi BD para probarlo...
Sin embargo, me pidieron AJAX... Pregunta: ¿puede adaptarse este código a la funcionalidad de AJAX?

Segundo Serrano dijo...

Hola María Florencia,

seguro que sí, y la forma más rápida sería que uses ASP.NET ajax, para este caso pondrías un control scriptmanager en la página y luego envolverías todo el código aspx dentro de un control updatepanel, algo así:
[form]
[scriptmanager][/scriptmanager]
[updatepanel]
[contenttemplate]
.....codigo va aquí........
[/contenttemplate]
[/updatepanel]
[/form]

Saludos.

María Florencia dijo...

Gracias por tu respuesta... ¡¡estoy en eso!!
Quería asegurarme antes de iniciar las modificaciones

María Florencia dijo...

Hola, Segundo. Nuevamente te consulto. Ahora, por algo que escapa completamente a mis conocimientos (y espero puedas ayudarme). Empecé trabajando en una aplicación con VS2010. Como no conseguí hosting con las características para implementarlas, tuve que convertirla a .net 2 :| Además de la millonada de referencias que desaparecieron -que, de a poco, voy resolviendo- me arroja un error constante que dice: "No se encuentran los ensamblados de referencia de la versión de .NET Framework de destino; asegúrese de que están instalados o seleccione una versión de destino válida."
La verdad, te molesto porque no doy en la tecla. ¿Puede haber algún sitio en el que encuentre orientación para esta conversión que hice? Gracias de antemano.

Segundo Serrano dijo...

Hola María Florencia,

qué quieres decir con convertirla a .net 2? significa que le cambiaste la versión al proyecto y entonces surgieron muchos errores?

hmmm, si es así... te recomendaría que hagas la revés: creas un proyecto en .NET 2.0 y luego recién vayas jalando la funcionalidad de a pocos.

Por otro lado, el post que yo presenté aquí es totalmente compatible con .NET 2.0

La otra forma de ayudarte sería que me envíes tu código a sserrano[@]jabs[.]com[.]pe para darle una chequeada.

Saludos

DACM145 dijo...

Hola que tal.. pues despues de buscar en varios post, este ha sido un ejemplo muy practico y facil de comprender.. soy nuevo en ASP.net y quiesiera saber como podria hacer para que deacuerdo a una lista de marcas pueda elegir los productos y agregarlos al carro y luego cambiar de marca y elegir los demas prodcutos.... y las marcas y los prodcutos se me carguen desde la Base de datos se SQLSERVER2008...Gracias....

Segundo Serrano dijo...

Hola DACM145,

al decir marcas supongo que te refieres a marcas de producto... bueno pues, podrás poner un dropdownList arriba del carrito, el dropdownlist tendría la lista de marcas de productos... y cada vez que seleccionas otra marca, se cargan nuevos productos.

Para eso tendrías que utilizar el evento SelectedIndexChanged del dropdownlist.

Saludos.

DACM145 dijo...

Hola Segundo Serrano P si entiendo lo de el DropdowList, estube probando y logre cargar los productos referentes a las marcas.. pero ya que tengo demaciadas marcas.. me lo pidieron que Cargara todas las marcas en un Grid o tabla la opcion mas sencilla... y Seleccione la Marca y en el otro me muestre los productos de solo esa marca y agrego los productos de esa marca al carrito y a su sucesibamente con diferentes marcas y sus productos... pero que unas vez que ya alla elegido los productos de cierta y al momento de elegir los de la otra no me lo borre solo que me los acumule... Gracias...

Segundo Serrano dijo...

Hola DACM145,

lograste hacer lo que necesitabas?
si aún no lo has hecho, porfa puedes subir una imagen a algún lado para poder visualizarlo cómo es que quieres que finalmente quede?

Saludos

LI. Alfonso Flores dijo...

Que tal, muy buen Post, tendras la misma el mismo proyecto pero en C#?

Muchas gracias, realmente muy bueno.

Segundo Serrano dijo...

Hola LI. Alfonso Flores,

no tengo el proyecto en C#, pero puedes usar este convertidor de código:
http://converter.telerik.com/

si tienes alguna duda, comentas?

Saludos

Unknown dijo...

hola que tal . estuve trabajando con este codigo pero la verdad no consigo ingresarle una imagen ya que el control asp:repeat bloqua todo el campo para ingresarlo manual. lo otro seria , supongo , agregandolo por la clase , pero la verdad no le he conseguido. si me pudieran ayudar con eso les estaria muy agradecido

Segundo Serrano dijo...

hola Edson Farias,
sube el código de tu repeater a algún lugar y luego pásame el enlace para darle una chequeadita y te aviso.

Saludos

Unknown dijo...

mira ahi esta el repeater por el lado de html. intente agregando un campo imagen en la clase Product y modificando el codigo de atras de visual.net pero nada. si se te ocurre otra forma , porque con esta me duplica la misma imagen para abajo, te lo agradeceria mucho. saludos
asp:Repeater ID="rptProducts" runat="server">
HeaderTemplate>


table>
tr>
th>
Producto
/th>
th>
Precio
/th>
th>
/th>
/tr>
/HeaderTemplate>
ItemTemplate>
tr>
td style="width: 85%">
asp:Image ID="image1" runat="server" ImageUrl="~/imagenes/torta chocolate.jpg" Height="112px" Width="125px" />
<%# Eval("ProductName")%>

/td>

td style="white-space: nowrap">
$ <%# Eval("Price")%>
/td>
td>
asp:Button ID="btnAddToCart" CommandArgument='<%# Eval("ProductID")%>' runat="server" Text="+ Agregar al carrito" />
/td>
/tr>
/ItemTemplate>
FooterTemplate>
/table>
/FooterTemplate>
/asp:Repeater>

Unknown dijo...
Este comentario ha sido eliminado por el autor.
Unknown dijo...

hola amigos .. en esta oportunidad les venia a consultar como puedo recorrer el repeater para obtener los datos de los productos seleccionado, ejemplo nombre del producto , codigo del producto . para asi poder pasarla a alguna variable y finalmente pasarla a la base de datos . lo otro seria recorrer el LIST del shoppingcart.getall() donde estan guardados por listas .. alguna ayuda de como hacer esto ?? gracias

Segundo Serrano dijo...

Hola Edson,

sería algo más o menos así:
For each prod as ProductOfTheShoppingCart in ShoppingCart.GetAll
dim id as integer = prod.ProductID
dim Price as Decimal = prod.Price
next

Lo he hecho a ojo de buen cubero... así que espero que esté correcto el código.

Saludos

Unknown dijo...

excelente segundo gracias !! me guarda perfect .
soy nuevo en esto de la programcion segundo , pero no abusare de tu confianza . te hara una ultima consulta.
tengo este codigo , pero creo que es para guardar solo un producto . como se haria para mandar guardar varios productos a la base de datos ????

For Each prod As ProductOfTheShoppingCart In ShoppingCart.GetAll

'Cantidad de productos
'**********************************************
Dim txtQuantity As TextBox = DirectCast(FindControl("txtQuantity"), TextBox)
Dim Quantity As Integer = 1
If Not IsNothing(txtQuantity) Then Quantity = txtQuantity.Text


Dim estado_venta As String = "pendiente"
total1.Text = ShoppingCart.Total
Dim total_compra As String
total_compra = total1.Text
Dim descuento As String = 0
' Dim resultado As Integer



Dim id As Integer = prod.ProductID
Dim Price As Decimal = prod.Price
Dim precio As String = Convert.ToString(Price)
nombre = prod.ProductName
resultado = conect.InsertarDetalleVenta(lbldetalle.Text, lblnumero.Text, cbocodigo, nombre, Quantity, descuento, total_compra, TextBox1.Text, TextBox5.Text, TextBox6.Text, TextBox3.Text, TextBox4.Text, TextBox2.Text, TextBox7.Text, estado_venta, TextBox9.Text, precio)



Next
donde nombre , quantity y cbo codigo corresponden a los datos de los productos. lo demas son datos del cliente.

Segundo Serrano dijo...

Hola Edson Farias,

veo que estas usando un bucle For para insertar los productos a la bd... entonces el còdigo està bien.

què parte no se ejecuta bien?

Saludos

Estefania dijo...

hola, buen proyecto solo tengo una pregunta solo me aparecen los titulos pero la tabla no, hice algo mal?

Segundo Serrano dijo...

hola Estefania,

hmmm, si no aparece la tabla (la tabla está allí pero no se ve) puede ser que no esté aplicando los estilos css a la tabla... verifica por ese lado, si el problema no va por allí, a ver si puedes compartir tu código para darle una chequeada.

Saludos

Don Pumba dijo...

Hola amigo tengo un problema, los rptProducts y rptShoppingCart me toman como no declarados, tengo vb 2010, algun tipo de solucion