Reputation: 18694
I have an edit box, defined like this:
<input class="change-handled form-control" type-id="@sub.CategoryTypeId" sub-category-id="@sub.SubCategoryId" data-id="@sub.CategoryBudgetId" style="text-align: right; width: 100%" type="number" value="@(sub.BudgetAmount.HasValue ? sub.BudgetAmount.ToString() : "")" />
In Javascript, I get the data-id value successfully like this:
var dataId = $(this).attr('data-id');
I now need to set it to a different value. I am trying:
$(this).setAttribute("data-id", 5);
But it seems the data-id never gets set to the value I pass. How can I set the data-id value of my editbox?
Full code of the function being used. (Note, no error checking yet):
$('body').on('change', 'input.change-handled', UpdateTotals);
function UpdateTotals() {
var dataId = $(this).attr('data-id');
var categoryId = $(this).attr('sub-category-id');
var value = $(this).val();
var totalExp = 0;
var totalInc = 0;
var $changeInputs = $('input.change-handled');
$changeInputs.each(function (idx, el) {
if ($(el).attr('type-id') == 2) {
totalInc += Number($(el).val());
}
if ($(el).attr('type-id') == 1) {
totalExp += Number($(el).val());
}
});
$(this).val(numberWithCommas(value));
$('#budgettedExpenseValue').text(numberWithCommas(totalExp));
$('#budgettedIncomeValue').text(numberWithCommas(totalInc));
$('#budgettedAvailableValue').text(numberWithCommas(totalInc - totalExp));
$.ajax({
url: '@Url.Action("SaveBudgetValue", "Budget")',
type: "POST",
contentType: "application/json",
data: JSON.stringify({ budgetCategoryId: dataId, catgoryId: categoryId, month: 4, year: 2015, value: value }),
cache: false,
async: true,
success: function (result) {
if (result.Success == 'true') {
$(this).attr("data-id", result.Id);
alert("Saved! " + result.Id.toString());
} else {
alert("Failed");
}
},
error: function () {
alert("Oh no...");
}
});
The code, after an edit box of the class type is edited, sums up all the income boxes (Decorated with a type-id = 1), and updates a field, and all the expense boxes (type-id = 2) and updates a separate field.
It then saves the data with a json call to my controller. If it's a new entry, data-id would have been NULL. The save method returns the primary key of the value saved. That value is displayed in my alert, and is supposed to be assigned to the edit boxe's data-id. But - isn't.
Upvotes: 0
Views: 1176
Reputation: 1074365
Re your update
The problem is that in the ajax
success callback, this
doesn't refer to the element anymore.
Two ways to fix that, and a third way that will be available in ES6:
Assign this
, or more usefully $(this)
, to a variable that you use in the success handler (and elsewhere, no need to constantly call $()
repeatedly on the same element):
function UpdateTotals() {
var input = $(this); // <========== Save it here
// ...
$.ajax({
// ...
success: function (result) {
// ...
if (result.Success == 'true') {
input.attr("data-id", result.Id); // <========= Use it here
alert("Saved! " + result.Id.toString());
} else {
alert("Failed");
}
}
});
// ...
}
Use Function#bind
(an ES5 feature, but it can be shimmed for really old browsers) to make this
within the callback the same as this
outside it:
function UpdateTotals() {
// ...
$.ajax({
// ...
success: function (result) {
// ...
if (result.Success == 'true') {
$(this).attr("data-id", result.Id);
alert("Saved! " + result.Id.toString());
} else {
alert("Failed");
}
}.bind(this) // <=========== Note
});
// ...
}
In ES6, we'll have arrow functions, which unlike normal functions inherit the this
of the context in which they're created. So in ES6, you could do this:
// **ES6 ONLY**
function UpdateTotals() {
// ...
$.ajax({
// ...
success: (result) => { // <==== Arrow function syntax
// ...
if (result.Success == 'true') {
$(this).attr("data-id", result.Id);
alert("Saved! " + result.Id.toString());
} else {
alert("Failed");
}
}
});
// ...
}
I'd lean toward #1, because you're doing a lot of repeated $(this)
anyway, so just as well to do var input = $(this);
once and then use input
throughout.
More about this
on my blog:
Original answer pre-update:
Since you're using jQuery, you set an attribute with attr
, like this:
$(this).attr("data-id", 5);
Live Example:
var input = $("input");
snippet.log("Before: " + input.attr("data-id"));
input.attr("data-id", 5);
snippet.log("After (jQuery): " + input.attr("data-id"));
snippet.log("After (DOM): " + input[0].getAttribute("data-id"));
snippet.log("Element's HTML (after): " + input[0].outerHTML);
<input class="change-handled form-control" type-id="@sub.CategoryTypeId" sub-category-id="@sub.SubCategoryId" data-id="@sub.CategoryBudgetId" style="text-align: right; width: 100%" type="number" value="@(sub.BudgetAmount.HasValue ? sub.BudgetAmount.ToString() : "")" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Or you can just use the DOM directly, by not wrapping the element in a jQuery wrapper:
this.setAttribute("data-id", 5);
Note that in either case, even though you're giving a number as the value, the value will end up being a string (as attributes only store strings).
You'll get people telling you to use data
, but data
is not just a way to access data-*
attributes, even though many people make that mistake. It might be useful for your end goal, though, depending on what that is. The jQuery data
function manages a cache of data that it associates with the element. The values data
manages are initialized from data-*
attributes, but data
never writes to data-*
attributes. If you're just trying to update attribute values, use attr
. If you're trying to do something more complex and it's not important that the values get written back to the element as attributes, look at the docs for data
and see whether it might be useful for you. (For one thing, the values data
manages can be types other than strings.)
Upvotes: 3
Reputation: 943569
You are putting your code in the success
function where this
will be some sort of jQuery ajax object and not an HTML element.
You need to store this
in a variable outside the ajax call and then use that variable.
e.g.
var that = this;
$.ajax({
Then:
setAttribute
is a DOM method, not a jQuery method.
Either:
$(that).attr("data-id", 5);
or (assuming this
is a Element object):
that.setAttribute("data-id", 5);
Upvotes: 3