Jquery data attribuut werkt niet zoals verwacht
Ik heb een formulier gemaakt, waarin dynamisch velden worden toegevoegd, met erachter een knop om de regel weer te verwijderen. Dit doe ik doofmiddel van data attribute in HTML waarbij ik een regelnummer toevoeg.
Nu werkt het dynamisch toevoegen van een regel, en ik kan een al bestaande regel verwijderen maar zodra ik een nieuwe regel toevoeg kan ik die regel niet meer verwijderen
De jQuery die ik gebruik voor het toevoegen van extra velden en het verwijderen ervan, hierbij is de variabel fieldcounter een waarde waarmee ik begin met invoegen van extra velden
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
$('.removeProduct').click(function(e) {
// Determinate if we need to add extra fields or not
var productRule = ($(this).data('remove'));
console.log("Clicked removeProduct");
console.log(productRule);
$('#modalRemoveButton').click(function(e) {
console.log("Called removeProduct");
console.log("ProductRule 1 " + productRule);
if($('.productName:visible').length == 1) {
$('#removeRuleError').modal('show');
console.log("Show error modal");
} else {
console.log("ProductRule 2 " + productRule);
$("input[name='removed["+ productRule + "]'").val('1');
$('#productLine' + productRule).hide('slow');
console.log("Removed product");
}
});
});
/**************************************************************************
* dd extra fields to the product pages.
*
* @ Attribute(s) fields
* @ Usage Set fields to true, to add extra fields
*
***************************************************************************/
$('#addField').click(function(e) {
var addExtraFields = $(this).data('fields');
var fields = '<div class="row" id="productLine'+ fieldStart +'"><div class="col-md-4"><input class="form-control productName" placeholder="Productnaam" name="productName['+ fieldStart +']" type="text"></div><div class="col-md-1"><input class="form-control" placeholder="Aantal" name="amount['+ fieldStart +']" type="text"></div><div class="col-md-1" style="width: 9.5%"><input class="form-control price" placeholder="Prijs" name="price['+ fieldStart +']" type="text"></div>';
// If there are extra fields required add them
if(addExtraFields) {
fields += '<div class="col-md-1"><input class="form-control" name="removed['+ fieldStart +']" type="text" value="0"></div><div class="col-md-1"><a data-toggle="modal" data-target="#removeRule"><div id="'+ fieldStart +'" class="removeProduct btn btn-green glyphicon glyphicon-trash trashcan"></div></a></div>';
}
// Close row
fields += '</div>';
// Append the extra fields
$('#extraFields').append(fields);
$('#'+ fieldStart).attr("data-remove", fieldStart);
// Update the readonly state of the price textbox
changeDisabledStatePrice();
fieldStart++;
});
// Determinate if we need to add extra fields or not
var productRule = ($(this).data('remove'));
console.log("Clicked removeProduct");
console.log(productRule);
$('#modalRemoveButton').click(function(e) {
console.log("Called removeProduct");
console.log("ProductRule 1 " + productRule);
if($('.productName:visible').length == 1) {
$('#removeRuleError').modal('show');
console.log("Show error modal");
} else {
console.log("ProductRule 2 " + productRule);
$("input[name='removed["+ productRule + "]'").val('1');
$('#productLine' + productRule).hide('slow');
console.log("Removed product");
}
});
});
/**************************************************************************
* dd extra fields to the product pages.
*
* @ Attribute(s) fields
* @ Usage Set fields to true, to add extra fields
*
***************************************************************************/
$('#addField').click(function(e) {
var addExtraFields = $(this).data('fields');
var fields = '<div class="row" id="productLine'+ fieldStart +'"><div class="col-md-4"><input class="form-control productName" placeholder="Productnaam" name="productName['+ fieldStart +']" type="text"></div><div class="col-md-1"><input class="form-control" placeholder="Aantal" name="amount['+ fieldStart +']" type="text"></div><div class="col-md-1" style="width: 9.5%"><input class="form-control price" placeholder="Prijs" name="price['+ fieldStart +']" type="text"></div>';
// If there are extra fields required add them
if(addExtraFields) {
fields += '<div class="col-md-1"><input class="form-control" name="removed['+ fieldStart +']" type="text" value="0"></div><div class="col-md-1"><a data-toggle="modal" data-target="#removeRule"><div id="'+ fieldStart +'" class="removeProduct btn btn-green glyphicon glyphicon-trash trashcan"></div></a></div>';
}
// Close row
fields += '</div>';
// Append the extra fields
$('#extraFields').append(fields);
$('#'+ fieldStart).attr("data-remove", fieldStart);
// Update the readonly state of the price textbox
changeDisabledStatePrice();
fieldStart++;
});
De HTML:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<div class="row" id="productLine1">
<div class="col-md-4">
<input class="form-control productName" name="productName[1]" type="text">
</div>
<div class="col-md-1">
<input class="form-control" name="amount[1]" type="text">
</div>
<div class="col-md-1" style="width: 9.5%;">
<input class="form-control" name="price[1]" type="text">
</div>
<div class="col-md-1">
<input class="form-control" name="removed[1]" type="text">
</div>
<div class="col-md-1">
<a data-toggle="modal" data-target="#removeRule">
<div class="removeProduct btn btn-green glyphicon glyphicon-trash trashcan" data-remove="1"></div>
</a>
</div>
</div>
<div class="col-md-4">
<input class="form-control productName" name="productName[1]" type="text">
</div>
<div class="col-md-1">
<input class="form-control" name="amount[1]" type="text">
</div>
<div class="col-md-1" style="width: 9.5%;">
<input class="form-control" name="price[1]" type="text">
</div>
<div class="col-md-1">
<input class="form-control" name="removed[1]" type="text">
</div>
<div class="col-md-1">
<a data-toggle="modal" data-target="#removeRule">
<div class="removeProduct btn btn-green glyphicon glyphicon-trash trashcan" data-remove="1"></div>
</a>
</div>
</div>
Gewijzigd op 15/06/2017 22:11:41 door Endreaw nvt
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
function addRemoveEvent() {
$('.removeProduct').unbind("click");
$('.removeProduct').click(function(e) {
// Determinate if we need to add extra fields or not
var productRule = ($(this).data('remove'));
console.log("Clicked removeProduct");
console.log(productRule);
$('#modalRemoveButton').click(function(e) {
console.log("Called removeProduct");
console.log("ProductRule 1 " + productRule);
if($('.productName:visible').length == 1) {
$('#removeRuleError').modal('show');
console.log("Show error modal");
} else {
console.log("ProductRule 2 " + productRule);
$("input[name='removed["+ productRule + "]'").val('1');
$('#productLine' + productRule).hide('slow');
console.log("Removed product");
}
});
});
}
addRemoveEvent();
/**************************************************************************
* dd extra fields to the product pages.
*
* @ Attribute(s) fields
* @ Usage Set fields to true, to add extra fields
*
***************************************************************************/
$('#addField').click(function(e) {
var addExtraFields = $(this).data('fields');
var fields = '<div class="row" id="productLine'+ fieldStart +'"><div class="col-md-4"><input class="form-control productName" placeholder="Productnaam" name="productName['+ fieldStart +']" type="text"></div><div class="col-md-1"><input class="form-control" placeholder="Aantal" name="amount['+ fieldStart +']" type="text"></div><div class="col-md-1" style="width: 9.5%"><input class="form-control price" placeholder="Prijs" name="price['+ fieldStart +']" type="text"></div>';
// If there are extra fields required add them
if(addExtraFields) {
fields += '<div class="col-md-1"><input class="form-control" name="removed['+ fieldStart +']" type="text" value="0"></div><div class="col-md-1"><a data-toggle="modal" data-target="#removeRule"><div id="'+ fieldStart +'" class="removeProduct btn btn-green glyphicon glyphicon-trash trashcan"></div></a></div>';
}
// Close row
fields += '</div>';
// Append the extra fields
$('#extraFields').append(fields);
$('#'+ fieldStart).attr("data-remove", fieldStart);
// Update the readonly state of the price textbox
changeDisabledStatePrice();
fieldStart++;
addRemoveEvent();
});
$('.removeProduct').unbind("click");
$('.removeProduct').click(function(e) {
// Determinate if we need to add extra fields or not
var productRule = ($(this).data('remove'));
console.log("Clicked removeProduct");
console.log(productRule);
$('#modalRemoveButton').click(function(e) {
console.log("Called removeProduct");
console.log("ProductRule 1 " + productRule);
if($('.productName:visible').length == 1) {
$('#removeRuleError').modal('show');
console.log("Show error modal");
} else {
console.log("ProductRule 2 " + productRule);
$("input[name='removed["+ productRule + "]'").val('1');
$('#productLine' + productRule).hide('slow');
console.log("Removed product");
}
});
});
}
addRemoveEvent();
/**************************************************************************
* dd extra fields to the product pages.
*
* @ Attribute(s) fields
* @ Usage Set fields to true, to add extra fields
*
***************************************************************************/
$('#addField').click(function(e) {
var addExtraFields = $(this).data('fields');
var fields = '<div class="row" id="productLine'+ fieldStart +'"><div class="col-md-4"><input class="form-control productName" placeholder="Productnaam" name="productName['+ fieldStart +']" type="text"></div><div class="col-md-1"><input class="form-control" placeholder="Aantal" name="amount['+ fieldStart +']" type="text"></div><div class="col-md-1" style="width: 9.5%"><input class="form-control price" placeholder="Prijs" name="price['+ fieldStart +']" type="text"></div>';
// If there are extra fields required add them
if(addExtraFields) {
fields += '<div class="col-md-1"><input class="form-control" name="removed['+ fieldStart +']" type="text" value="0"></div><div class="col-md-1"><a data-toggle="modal" data-target="#removeRule"><div id="'+ fieldStart +'" class="removeProduct btn btn-green glyphicon glyphicon-trash trashcan"></div></a></div>';
}
// Close row
fields += '</div>';
// Append the extra fields
$('#extraFields').append(fields);
$('#'+ fieldStart).attr("data-remove", fieldStart);
// Update the readonly state of the price textbox
changeDisabledStatePrice();
fieldStart++;
addRemoveEvent();
});
Ik heb een kleine aanpassing in je code gedaan die er voor zorgt dat, elke keer als je een element toevoegd, de remove trigger opnieuw op de elementen word gezet.
Probleem is denk ik als volgt :
Laten we beginnen met een aanname, je voert je code uit op document.ready (of iets van gelijke strekking).
Als je dat doet, word het click event toegevoegd voor alle elementen met de class "removeProduct" die op dat moment op je pagina staan.
Echter als je een nieuw element toevoegd zal die dit event nog niet hebben, dus moet je de betreffende code opnieuw uitvoeren. (zoals ik hierboven heb gedaan).
Op het moment dat je dat doet wil je eerst het bestaande click event weg halen (aannemende dat er maar 1 click event op elementen met de class "removeProduct" zit).
De reden dat je dat wil doen is omdat je anders het event 2 (of meer) keer op 1 element hebt staan, en dit kan hele creatieve bugs opleveren. Dus je verwijderd eerst het click event, en vervolgens voeg je het opnieuw toe
Toevoeging op 16/06/2017 07:40:43:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
function addRemoveEvent() {
$('.removeProduct').unbind("click");
$('.removeProduct').click(function(e) {
// Determinate if we need to add extra fields or not
var productRule = ($(this).data('remove'));
console.log("Clicked removeProduct");
console.log(productRule);
$('#modalRemoveButton').click(function(e) {
console.log("Called removeProduct");
console.log("ProductRule 1 " + productRule);
if($('.productName:visible').length == 1) {
$('#removeRuleError').modal('show');
console.log("Show error modal");
} else {
console.log("ProductRule 2 " + productRule);
$("input[name='removed["+ productRule + "]'").val('1');
$('#productLine' + productRule).hide('slow');
console.log("Removed product");
}
});
});
}
addRemoveEvent();
/**************************************************************************
* dd extra fields to the product pages.
*
* @ Attribute(s) fields
* @ Usage Set fields to true, to add extra fields
*
***************************************************************************/
$('#addField').click(function(e) {
var addExtraFields = $(this).data('fields');
var fields = '<div class="row" id="productLine'+ fieldStart +'"><div class="col-md-4"><input class="form-control productName" placeholder="Productnaam" name="productName['+ fieldStart +']" type="text"></div><div class="col-md-1"><input class="form-control" placeholder="Aantal" name="amount['+ fieldStart +']" type="text"></div><div class="col-md-1" style="width: 9.5%"><input class="form-control price" placeholder="Prijs" name="price['+ fieldStart +']" type="text"></div>';
// If there are extra fields required add them
if(addExtraFields) {
fields += '<div class="col-md-1"><input class="form-control" name="removed['+ fieldStart +']" type="text" value="0"></div><div class="col-md-1"><a data-toggle="modal" data-target="#removeRule"><div id="'+ fieldStart +'" class="removeProduct btn btn-green glyphicon glyphicon-trash trashcan"></div></a></div>';
}
// Close row
fields += '</div>';
// Append the extra fields
$('#extraFields').append(fields);
$('#'+ fieldStart).attr("data-remove", fieldStart);
// Update the readonly state of the price textbox
changeDisabledStatePrice();
fieldStart++;
addRemoveEvent
});
$('.removeProduct').unbind("click");
$('.removeProduct').click(function(e) {
// Determinate if we need to add extra fields or not
var productRule = ($(this).data('remove'));
console.log("Clicked removeProduct");
console.log(productRule);
$('#modalRemoveButton').click(function(e) {
console.log("Called removeProduct");
console.log("ProductRule 1 " + productRule);
if($('.productName:visible').length == 1) {
$('#removeRuleError').modal('show');
console.log("Show error modal");
} else {
console.log("ProductRule 2 " + productRule);
$("input[name='removed["+ productRule + "]'").val('1');
$('#productLine' + productRule).hide('slow');
console.log("Removed product");
}
});
});
}
addRemoveEvent();
/**************************************************************************
* dd extra fields to the product pages.
*
* @ Attribute(s) fields
* @ Usage Set fields to true, to add extra fields
*
***************************************************************************/
$('#addField').click(function(e) {
var addExtraFields = $(this).data('fields');
var fields = '<div class="row" id="productLine'+ fieldStart +'"><div class="col-md-4"><input class="form-control productName" placeholder="Productnaam" name="productName['+ fieldStart +']" type="text"></div><div class="col-md-1"><input class="form-control" placeholder="Aantal" name="amount['+ fieldStart +']" type="text"></div><div class="col-md-1" style="width: 9.5%"><input class="form-control price" placeholder="Prijs" name="price['+ fieldStart +']" type="text"></div>';
// If there are extra fields required add them
if(addExtraFields) {
fields += '<div class="col-md-1"><input class="form-control" name="removed['+ fieldStart +']" type="text" value="0"></div><div class="col-md-1"><a data-toggle="modal" data-target="#removeRule"><div id="'+ fieldStart +'" class="removeProduct btn btn-green glyphicon glyphicon-trash trashcan"></div></a></div>';
}
// Close row
fields += '</div>';
// Append the extra fields
$('#extraFields').append(fields);
$('#'+ fieldStart).attr("data-remove", fieldStart);
// Update the readonly state of the price textbox
changeDisabledStatePrice();
fieldStart++;
addRemoveEvent
});
Ik heb een kleine aanpassing in je code gedaan die er voor zorgt dat, elke keer als je een element toevoegd, de remove trigger opnieuw op de elementen word gezet.
Probleem is denk ik als volgt :
Laten we beginnen met een aanname, je voert je code uit op document.ready (of iets van gelijke strekking).
Als je dat doet, word het click event toegevoegd voor alle elementen met de class "removeProduct" die op dat moment op je pagina staan.
Echter als je een nieuw element toevoegd zal die dit event nog niet hebben, dus moet je de betreffende code opnieuw uitvoeren. (zoals ik hierboven heb gedaan).
Op het moment dat je dat doet wil je eerst het bestaande click event weg halen (aannemende dat er maar 1 click event op elementen met de class "removeProduct" zit).
De reden dat je dat wil doen is omdat je anders het event 2 (of meer) keer op 1 element hebt staan, en dit kan hele creatieve bugs opleveren. Dus je verwijderd eerst het click event, en vervolgens voeg je het opnieuw toe
Gewijzigd op 16/06/2017 07:41:12 door Jacco Engel
Bedankt voor de oplossing, en de duidelijke uitleg. Nu begrijp ik wat er mis ging. Het werkt naar behoren :)
Dan zou je er denk ik al zijn als je de eerste regel
$('.removeProduct').click(function(e) {
vervangt door
$(document).on('click', '.removeProduct', function(e) {
als er nu "ergens" op de pagina (document) geklikt wordt (die click), dan wordt gekeken of (.removeProduct) van toepassing is.
Maar de listener ligt op het hele document. En pas na de click wordt gezocht.
In de oorspronkelijke situatie wordt de listener aan het betreffende element gekoppeld. Is dat element ten tijde van het koppelen niet aanwezig -> geen listener.
Bijkomend voordeel voor de browser is, als het een lijst van 4000 regels is heb je niet 4000 listeners, maar slechts 1.
(ipv document zou je ook nog een kleiner element kunnen kiezen, maar met document ben je er denk ik ook wel)
Ivo P op 16/06/2017 11:06:05:
Om dit hele proces te voorkomen, is het misschien handiger om 1 listener te hebben voor het click event, en dan te controleren of het geclickte element de class removeProduct had.
Dan zou je er denk ik al zijn als je de eerste regel
$('.removeProduct').click(function(e) {
vervangt door
$(document).on('click', '.removeProduct', function(e) {
als er nu "ergens" op de pagina (document) geklikt wordt (die click), dan wordt gekeken of (.removeProduct) van toepassing is.
Maar de listener ligt op het hele document. En pas na de click wordt gezocht.
In de oorspronkelijke situatie wordt de listener aan het betreffende element gekoppeld. Is dat element ten tijde van het koppelen niet aanwezig -> geen listener.
Bijkomend voordeel voor de browser is, als het een lijst van 4000 regels is heb je niet 4000 listeners, maar slechts 1.
(ipv document zou je ook nog een kleiner element kunnen kiezen, maar met document ben je er denk ik ook wel)
Dan zou je er denk ik al zijn als je de eerste regel
$('.removeProduct').click(function(e) {
vervangt door
$(document).on('click', '.removeProduct', function(e) {
als er nu "ergens" op de pagina (document) geklikt wordt (die click), dan wordt gekeken of (.removeProduct) van toepassing is.
Maar de listener ligt op het hele document. En pas na de click wordt gezocht.
In de oorspronkelijke situatie wordt de listener aan het betreffende element gekoppeld. Is dat element ten tijde van het koppelen niet aanwezig -> geen listener.
Bijkomend voordeel voor de browser is, als het een lijst van 4000 regels is heb je niet 4000 listeners, maar slechts 1.
(ipv document zou je ook nog een kleiner element kunnen kiezen, maar met document ben je er denk ik ook wel)
Is inderdaad ook een oplossing, al ben ik er zelf niet zo'n fan van omdat je click handler dan onoverzichtelijk word als je veel events krijgt. Maar dat is meer kwestie van smaak dan iets anders
ipv dat de handlers keer op keer toegevoegd en verwijderd worden.
En daarbij: qua code is het gelijk, op de ene regel na.
Wel heb je gelijk dat de browser bij elke klik ergens op het document alle mogelijke opties
$(document).on('click', '****', function(e) {
na moet lopen of het geklikte element voldoet.
Heb je veel van die opties, dan zou je kunnen kijken of een
<div id="container"> </div> geplaatst kan worden om de betreffende elementen, mocht deze al missen
en dan gebruik maken van
$('#container').on('click', '.removeProduct', function(e) {
Toevoeging op 16/06/2017 13:38:10:
hier wordt het wel mooi uitgelegd:
https://stackoverflow.com/questions/8110934/direct-vs-delegated-jquery-on
Mja met name dat laatste, baken de gebieden af waarbinnen click-events actief zouden moeten zijn, $(document) als selectiegebied is mogelijk nogal overkill.
Maar als ik dat in de eerste post al zou noemen, zou het waarschijnlijk betekenen dat TS ook zijn htmlcode direct moet aanpassen.