Changing the text of a label with jquery with text () or html () does not work

1

I know that to change the value of a label it is valid with html () or text () but the problem is that it does not work. Let me explain:

The function of the program is that by double clicking on an element with the class ".item" that element is cloned and added to a div, that the stock is subtracted in one and that the price and number of items increase.

I define $ stockLblInicial and $ cantStockInicial when loading the page to check if there is stock and if there is a double click, if there is nothing then.

Loading the page:

    $(function(){

    $("#citem").val(0); //Ponemos el contador de items a cero cada vez que se refresque la pagina
    $("#cprice").val(0 + " €"); //Ponemos el valor del precio total a cero cada ves que se refresque la pagina 

    var $stockLblInicial = $(".stock", $(this)).text(); //Pillamos la etiqueta del stock 
    var $cantStockInicial = parseInt($stockLblInicial.slice(6)); //Cogemos solo el numero y lo pasamos a int 
    //Hago un slice ya que el label es tal que "Stock 10" y solo quiero el numero 

    //Si hay items en stock 
    if($cantStockInicial > 0){
        $(".item").on("dblclick", dobleClickItems);
    }else{
        return false;
    }
}); 

Within the doubleClick function we define $ stockLbl and $ cantStock because later the value of these variables will be trampled. In the function itself, it takes those values so that in purchase () the stock is subtracted in one and assigned to the text of the clicked item. The text does not change then it always catches like there are 10 items. The problem is not in the counter because it remains as it touches. The problem is directly does not change the text. I have tried with text () and with html () and it does not work.

    function dobleClickItems(){
    //Variable necesarias para clonar
    const $divCarrito = $("#cart_items"); //Pillamos el contenedor del carrito
    let $idItem = $(this).attr("id"); //Pillamos la id del item seleccionado (devuelve un string)
    let $clonedItem = $(this).clone(); //Clonamos el item 

    var $stockLbl = $(".stock", $(this)).text(); //Pillamos la etiqueta del stock 
    var $cantStock = parseInt($stockLbl.slice(6)); //Cogemos solo el numero y lo pasamos a int 

    let $precioLabel = $(".price", $(this)).text(); //Pillamos el precio del producto clickado
    let $precio = parseInt($precioLabel.slice(0, 4)); //Cogemos el numero y lo pasamos a int

    let $numItems = $("#citem").val(); //Pillamos el valor del input de la cantidad de elementos 
    parseInt($numItems); //Pasamos el valor a int para poder hacer operaciones

    //Pillamos el valor del input del precio total y lo pasamos a int tambien 
    let $precioTotal = parseInt($("#cprice").val().slice(0, 4));

    compra($cantStock, $numItems, $precioTotal, $precio);
    cloneItem($idItem, $clonedItem, $divCarrito);

    if($cantStock == 0){ //Si no quedan items le añadimos la clase "agotado" al item 
        $(".stock", $(this)).addClass("agotado");
    }
}

Here the function buys:

    function compra($cantStock, $numItems, $precioTotal, $precio){
    $cantStock--; //Contador para decrementar el valor del stock  
    $(".stock", $(this)).html("Stock " + $cantStock); //Reducimos en uno el numero de stock

    console.log("Cantidad en stock " + $cantStock);

    $numItems++; //Incrementamos el numero de items comprados
    $("#citem").val($numItems); //Aumentamos el numero de compras

    console.log($numItems);

    $precioTotal += $precio; //Al precio del input le vamos sumando el precio de todas la compras 
    $("#cprice").val($precioTotal + " €");
}

The console does not throw any problems, it's just that the label does not change it and I do not know why it can be. If someone could help me, I would be very grateful.

The html:

<!DOCTYPE html>
<html>
<head>
	<title>Carro de la compra con jQuery</title>
	<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
	<link rel="stylesheet" title="normal" href="css/carro.css" type="text/css" media="screen" />
	<!-- CDN JQuery de Google -->
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="http://code.jquery.com/jquery-1.9.0.min.js" 
			type="text/javascript"></script>
	<script src="scripts/carro.js" type="text/javascript"></script>
</head>
<body>
	<div id="item_container">
		<div class="item" id="i1">
			<img src="img/camiseta1.jpg" alt="descripción i1"/>
			<label class="title">Camiseta 1</label>
			<label class="price">20 €</label>
			<label class="stock">Stock 10</label>
		</div>
		<div class="item" id="i2">
			<img src="img/reloj2.jpg" alt="descripción i2"/>
			<label class="title">Reloj 2</label>
			<label class="price">24 €</label>
			<label class="stock">Stock 10</label>
		</div>
		<div class="clear"></div>
	</div>
	<div id="cart_container">
		<div id="cart_title">
			<span>Carrito</span>
			<div class="clear"></div>
		</div>
		<div id="cart_toolbar">
			<div id="cart_items" class="back"></div>
		</div>
		<div id="navigate">
			<div id="nav_left">
				<button id="btn_comprar" title="Confirma la compra de los artículos">Comprar</button>
				<button id="btn_prev" title="Desplaza el carrito hacia la izquierda">&lt;</button>
				<button id="btn_next" title="Desplaza el carrito hacia la derecha">&gt;</button>
				<button id="btn_clear" title="Vacia el carrito">Vaciar</button>
			</div>
			<div id="nav_right">
				<span class="sptext">
					<label>Compras </label><input id="citem" value="0" readonly title="Número de productos comprados"/>
				</span>
				<span class="sptext">
					<label>Precio </label><input id="cprice" value="0 €" readonly  title="Precio total de los productos comprados"/>
				</span>
			</div>
			<div class="clear"></div>
		</div>
	</div>
</body>
</html>

PS: If it were necessary the html I edit the question and I add it also.

EDIT: The error specifically is that I try to edit the label with class "stock" inside the div with class "item" but it does not. This I specifically do here: $(".stock", $(this)).html("Stock " + $cantStock); It is the second line of the purchase () function. I hope this clarifies it a bit more.

EDIT 2: I want to modify the label of the element that I click twice because of what the variable $ this is when I define $ stockLbl. What I want is to change the content of that label and access it through its ".stock" class. Specifically, I want to double click the number of the label is reduced by one. That is why I have a variable $ cantStock that I use as a counter and that is initialized when I make a split of the content of the label until I only have the number.

Equal seeing the layout as it is is understood a little better:

When you double click on one of the containers where the product is, the stock number should be reduced by 1.

    
asked by yonvela20 19.11.2018 в 11:29
source

2 answers

0

I propose a solution based on the use of attributes data-* . I do not think a code is correct in which you store values that are necessary for calculations along with words, as is the case of Stock . With the attributes data-* you can store in each div elements as the quantity in stock or the price as numbers and use those values for future calculations. And more professional things would be easier to implement, such as disabling the items when the stock reaches 0 .

In this fragment, the double clicks of div are heard and in each double click the stock is reduced by one.

Keep in mind that this code will be very useful also if you want to work with the price for example. Or if you want to pass the element clicked to another part, such as a shopping cart or something similar. And it will avoid having to be cleaning the contents of the label to obtain only the numerical value.

I have used pure Javascript code. You can use jQuery if you want, but it is recommended to avoid using external libraries when you can do it with pure JS (the code is faster).

I hope it will be useful for you. You can test its operation ...

/*Asignamos un listener a todos los elementos de la clase item*/
var elementsArray = document.querySelectorAll('.item');
elementsArray.forEach(function(elem) {
  elem.addEventListener("dblclick", dobleClick, false);
});
/*Esta es la función definida en el listener*/
function dobleClick() {
  /*Con dataset.[nombre] obtenemos el valor que hay en ese atributo*/
  var stockReduced = this.dataset.stock - 1;
  /*Actualizamos el atributo a [valor-1]*/ 
  this.dataset.stock= stockReduced;
  /*Referencia al label stock*/
  var lblStock = this.getElementsByTagName('label')[2];
  /*Actualizamos el valor numérico de forma dinámica*/
  lblStock.textContent = 'Stock ${stockReduced}';
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="item_container">
  <div class="item" id="i1" data-stock="10" data-price="20">
    <img src="img/camiseta1.jpg" alt="descripción i1" />
    <label class="title">Camiseta 1</label>
    <label class="price">20 €</label>
    <label class="stock">Stock 10</label>
  </div>
  <div class="item" id="i2" data-stock="10" data-price="24">

    <img src="img/reloj2.jpg" alt="descripción i2" />
    <label class="title">Reloj 2</label>
    <label class="price">24 €</label>
    <label class="stock">Stock 10</label>
  </div>
  <div class="clear"></div>
</div>
    
answered by 19.11.2018 / 13:17
source
1

The functionality is poorly stated for many reasons, but let's go immediately:

You have two non-event functions $(document).ready({...}) that should work according to their parameters and not coupled to what you define within the aforementioned block. This is correct , you do not want coupling or stepping on general variables within functions.

You declare a listener about $(".stock", $(this)) that refers to as many items as you have for sale. That's right , means that everyone has that behavior.

In particular, when you search

$(".stock", $(this))

Within $(function() {...}) this is the document. For what is interpreted as:

$(".stock", $(document))

The listener invokes a handler dobleClickItems . That's right , since this jQuery handler receives a reference to the item, so, within dobleClickItems , $(this) is the item that has been punctured.

Here comes the problem. Within dobleClickItems llamas to compra . But buying is a common and current function. It is not a jQuery handler. Within compra $(this) you have lost the reference to item , and you have even lost the reference to document . The interpreter is forced to assume that it is a reference to window , and

$(".stock", $(window))

Does not identify any items.

Proposed solution

First, you have N products. You want to check if they have inventory. If yes, you give them the clickable behavior. For this you should check the inventory of each product:

$(".item").each(function() {
  var inventario = ...;
  if(inventario > 0) {
    ... tienen comportamiento doble click...
  }
});

Now, to know if they have inventory, considering that the inventory is in a label, it does not seem right to use the text of the label that, badly, is designed to be a text and not a value. Within the label I would put an input so that it would be:

<label class="stock">Stock 
   <input type="text" readonly value="10">
</label>

And get the stock of each product using:

$(".item").each(function() {
  var inputInventario = $(this).find('input'); 
  var inventario = parseInt(inputInventario.val(), 10);
  if(inventario > 0) {
     $(this).on("dblclick", dobleClickItems);
  }
});

Now each product is clickable or not depending on its own stock, regardless of the product on the side.

When you go to buy, within dobleClickItems you have the reference to the item that has been punctured, so you could do, again:

function dobleClickItems() {
   var inputInventario = $(this).find('input');
   var inventario = parseInt(inputInventario.val(), 10);

   ... más cosas...   
}

And lower the inventory before executing the purchase. The purchase is an act that interacts with the cart and not with the inventory, you do not put responsibility on an area that is foreign:

function dobleClickItems() {
       var inputInventario = $(this).find('input');
       var inventario = parseInt(inputInventario.val(), 10);

    inventario--;
    inputInventario.val(inventario);

    compra($numItems, $precioTotal, $precio);       
}

Notice that I removed the reference to the amount of stock in the purchase function. On the other hand, I would also remove the calculation of the cart items from the dobleClickItems function. In the design, what is done with the items does not know what is done with the cart. What you do with the cart has no idea what you did with the items. Each function has a single responsibility and each other speaks according to the Demeter's law . The less each function knows what the other does, the better.

Aesthetically Produced Solution :

You may not want the inventory to look like an input box. No problem. You could use a label property (eg rel ) to store the available stock, and put a pseudo element that would display the amount of stock without touching the text , but using an attribute. For example, think that you define the stock of product 1 using:

<div class="item" id="i1">
   <label class="stock" rel="10">Stock </label>
</div>

And in the style sheet carro.css you put a pseudo element whose content is the attribute rel of the label:

.item .stock:after {
    content: attr(rel);
    width: 20px;
}

Then, when you would like to know the available stock you would use:

$(".item").each(function() {
  var relInventario = $(this).attr('rel'); 
  var inventario = parseInt(relInventario, 10);
  if(inventario > 0) {
     $(this).on("dblclick", dobleClickItems);
  }
});

And to modify the inventory:

inventario--;
$(this).attr('rel',inventario);

You will see that the pseudo element changes according to the property, without you touching the text:

    
answered by 19.11.2018 в 12:40