jQuery argument suddely changes into n.Event object - javascript

I have a dropdown on my page,which selected value I take like this:
<select id="campaign" class="form-control">
<option>Choose campaign</option>
<option value="createCampaign">Create new campaign</option>
<?php while($row=$resultForCampaigns->fetch_assoc()){
$campaignName=$row['campaign_name'];
echo "<option value=$campaignName>$campaignName</option>";
}?>
</select>
var campaign = $('#campaign option:selected').val();
But when I'm passing that same campaign value as a argument of new function, and do console.log(campaign) it says:
Here is the whole code:
$(document).ready(function() {
$('#campaign').change(function() {
var campaign = $('#campaign option:selected').val();
console.log(campaign);
if (campaign != 'Choose campaign') {
console.log(campaign);
$('#deleteCampaign').click(function(campaign) {
console.log(campaign);
var r = confirm("Are you absolutely sure you want to delete selected campaign?");
if (r == true) {
var data = {};
data.action2 = "deleteCampaign";
data.campaign = campaign;
$.ajax({
url: "../includes/adapter.php",
type: "POST",
dataType: "JSON",
data: data,
async: true,
success: function() {
if (data) {
console.log(data);
$('#poruka').append('<div class="alert alert-success"><strong>Success!</strong> You have successfully deleted campaign!</div>');
} else {
$('#poruka').append('<div class="alert alert-danger"><strong>Failure!</strong> Something went wrong with deleting your campaign! Please try again</div>');
}
}
});
}
});
}
});
});
So, console.log(campaign) after click on $('#deleteCampaign') turns value of campaign from one that I've gave it, to one that picture represents. Really don't know what's going on, so If anyone could explain me how to get correct value inside function that is tiggered by click, I would be very thankful.

The variable campaign is redefined when you use the same name as a function argument in a lower scope.
Variables are scoped to functions, and function arguments are considered variables, it would be the same as doing
var something = 'stuff';
function go() {
something = 'other stuff';
console.log(something); // obviously "other stuff"
}
The first argument for the click function in jQuery is the event object, you can't pass in anything else.
All you have to do is just remove the argument.
var campaign = $('#campaign option:selected').val();
$('#deleteCampaign').click(function() {
console.log(campaign); // still the value

Related

Knockout Determining dropdownlist selection and update text to database

I am working on binding some data retreive from database and then update it back to database. The database table is a bit weird in this case but I was given instruction to not modify the existing database.
The thing work as follow:
The database table contain both the GoldMemberCardNo and SilverMemberCardNo, in which only one of them is filled at a time (and another is null).
I am required to determine whether the member is GoldMemberCardHolder or SilverMemberCardHolder based on whether it is null and bind the correct one (both the member category and gold/silver card number) to the dropdownlist and text input on initial page load. The one and only way i am able to differentiate whether the member is gold member or silver member is to see whether the CardNo is filled for the particular member
The admin is then given permission to choose from the selection and enter the card number as they wish, and then submit the form.
Suppose, the user is previously an silver member card holder, and now is required to change to gold member card holder. After the admin fill in the required information, when update, the silver member card will be set to null and gold member card value is updated to database.
I have tried as following but getting stuck here. Since it is computed observable, the ko.observable will always be the same and will not listen to the changes when the value changes. Therefore, the value post is always the initial value. And i think my approach to this solution is pretty much bloated.
function MemberProfile() {
var self = this;
self.SilverMemberCardNo = ko.observable();
self.GoldMemberCardNo = ko.observable();
self.CardNo = ko.observable();
self.MemberCategory = ko.computed(function() {
if(self.SilverMemberCardNo() != null) {
return "0";
else if(self.GoldMemberCardNo() != null) {
return "1";
}
});
self.CardNo = ko.computed(function() {
if(self.SilverMemberCardNo() != null) {
return self.SilverMemberCardNo();
else if(self.GoldMemberCardNo() != null) {
return self.GoldMemberCardNo();
}
});
self.GetMemberProfile() = function() {
$.ajax({
dataType: 'json',
type: 'GET',
url: ...,
success: {
ko.mapping.fromJS(data, {}, self);
}
})
}
self.UpdateMemberProfile() = function() {
if(self.MemberCategory == "0") {
self.SilverMemberCardNo(self.CardNo);
self.GoldMemberCardNo(null)
}
else if (self.MemberCategory == "1") {
self.SilverMemberCardNo(null);
self.GoldMemberCardNo(self.CardNo)
}
$.ajax({
dataType: 'json',
type: 'PUT',
url: ...,
data: {
SilverMemberCardNo: self.SilverMemberCardNo,
GoldMemberCardNo: self.GoldMemberCardNo
......
}
}
}
ko.applyBindings(new MemberProfile());
// Data return from JSON
{
"SilverMemberCardNo": null
"GoldMemberCardNo": "123456789"
....
....
....
}
<select>
<option value="0" text="Silver Member" data-bind="value:MemberCategory"></option>
<option value="1" text="Gold Member" data-bind="value:MemberCategory"></option>
</select>
<input type="text" data-bind="CardNo" />
You could make MemberCategory a simple observable and set it's value using your logic in the function of the self.GetMemberProfile() success event.
function MemberProfile() {
var self = this;
self.CardNo = ko.observable();
self.MemberCategory = ko.observable();
self.GetMemberProfile() = function() {
$.ajax({
dataType: 'json',
type: 'GET',
url: ...,
success: {
ko.mapping.fromJS(data, {}, self);
if (self.SilverMemberCardNo() != null) {
self.MemberCategory("0");
} else if (self.GoldMemberCardNo() != null) {
self.MemberCategory("1");
}
}
})
}
self.UpdateMemberProfile() = function() {
var silverMemberCardNo;
var goldMemberCardNo;
if (self.MemberCategory == "0") {
silverMemberCardNo = self.CardNo();
goldMemberCardNo = null;
} else if (self.MemberCategory == "1") {
silverMemberCardNo = null;
goldMemberCardNo = self.CardNo();
}
$.ajax({
dataType: 'json',
type: 'PUT',
url: ...,
data: {
SilverMemberCardNo: silverMemberCardNo,
GoldMemberCardNo: goldMemberCardNo
}
}
}
Another thing to consider, which you may or may not be able to control, is that this logic would be more secure to execute on the server, instead of the client. Meaning take out all of that logic in javascript and do it on the server. Leaving the client to just present data and send it back.

Getting and Setting a data attribute in HTML

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.
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:
You must remember this
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.)
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);

what is causing this javascript code to function the way it is?

I know stackoverflow tends to shy away from "wall of text" posts, but I've been at this for about 4 hours and I can't figure it out, so I wanted to give as much information as possible.
I have a page with two input forms on it. Whenever I add text into the first one, the javascript function attached to the second input button runs, and I can't figure out why.
In my header I have two scripts:
<script type="text/javascript" src="/autocomplete/js/script.js"></script>
which contains:
function autocomplet() {
var min_length = 0; // min caracters to display the autocomplete
var keyword = $('#country_id').val();
if (keyword.length >= min_length) {
$.ajax({
url: 'capoInstantSearch.php',
type: 'POST',
data: {keyword:keyword},
success:function(data){
$('#country_list_id').show();
$('#country_list_id').html(data);
}
});
} else {
$('#country_list_id').hide();
}
}
// set_item : this function will be executed when we select an item
function set_item(item) {
// change input value
$('#country_id').val(item);
// hide proposition list
$('#country_list_id').hide();
$("#capoInfo").load("capoSingleReturn.php?q="+encodeURIComponent(item));
}
capoInstantSearch.php looks like this:
<?php
function connect() {
return new PDO('code here to connect'}
$pdo = connect();
$keyword = '%'.$_POST['keyword'].'%';
$sql = "SELECT statement is here....";
$query = $pdo->prepare($sql);
$query->bindParam(':keyword', $keyword, PDO::PARAM_STR);
$query->execute();
$list = $query->fetchAll();
foreach ($list as $rs) {
// put in bold the written text
$country_name = str_replace(strtoupper($_POST['keyword']), '<b>'.$_POST['keyword'].'</b>', $rs['quotePartNumber']);
// add new option
echo '<li onclick="set_item(\''.str_replace("'", "\'", $rs['quotePartNumber']).'\')">'.$country_name.'</li>';
}
?>
and
<script type="text/javascript" src="/autocomplete/js/script2.js"></script>
which contains:
function compCheck() {
var min_length = 0; // min caracters to display the autocomplete
var bootyTime = $('#comp_id').val();
if (bootyTime.length >= min_length) {
$.ajax({
url: 'capoInstantCompSearch.php',
type: 'POST',
data: {bootyTime:bootyTime},
success:function(data){
$('#comp_list_id').show();
$('#comp_list_id').html(data);
}
});
} else {
$('#comp_list_id').hide();
}
}
// set_item : this function will be executed when we select an item
function set_item(item) {
// change input value
$('#comp_id').val(item);
// hide proposition list
$('#comp_list_id').hide();
$("#compReturn").load("capoCompReturn.php?w="+encodeURIComponent(item));
}
Input Box 1:
<input id="country_id" type="text" placeholder="Enter a Part Number"
onsubmit="this.value=this.value.toUpperCase()" autocomplete="off" onkeyup="autocomplet()">
<ul id="country_list_id"></ul>
Input Box 2:
<input id="comp_id" type="text" onkeypress="this.value=this.value.toUpperCase()"
placeholder="Part Number 2" onkeyup="compCheck()"></h2>
<ul id="comp_list_id"></ul>
Ultimately, the contents of autocomplet() should be placed into this div
<div id="capoInfo" class="capoData"></div>
while the contents of compCheck() should be placed into
<div id="compReturn" class="blueBorder"></div>
When I type text into the first input box, it populates the <ul> country_list_id, and when I make a selection, it populates that answer into second input box on my page, then executes that code. I cannot figure out WHY it is doing this and it's driving me crazy....
It's because you have two functions that are in the global scope called "set_item"
You are defining your functions in the global scope, and the second is overwriting the first. You could solve this by namespacing (for lack of a better term) your functions by sticking them into an object.
For example,
script.js
var country = {
autocomplete: function() {
var min_length = 0; // min caracters to display the autocomplete
var keyword = $('#country_id').val();
if (keyword.length >= min_length) {
$.ajax({
url: 'capoInstantSearch.php',
type: 'POST',
data: {keyword:keyword},
success:function(data){
$('#country_list_id').show();
$('#country_list_id').html(data);
}
});
} else {
$('#country_list_id').hide();
}
},
// set_item : this function will be executed when we select an item
set_item: function(item) {
// change input value
$('#country_id').val(item);
// hide proposition list
$('#country_list_id').hide();
$("#capoInfo").load("capoSingleReturn.php?q="+encodeURIComponent(item));
}
}
script2.js
var comp = {
compCheck: function() {
var min_length = 0; // min caracters to display the autocomplete
var bootyTime = $('#comp_id').val();
if (bootyTime.length >= min_length) {
$.ajax({
url: 'capoInstantCompSearch.php',
type: 'POST',
data: {bootyTime:bootyTime},
success:function(data){
$('#comp_list_id').show();
$('#comp_list_id').html(data);
}
});
} else {
$('#comp_list_id').hide();
}
},
// set_item : this function will be executed when we select an item
set_item: function(item) {
// change input value
$('#comp_id').val(item);
// hide proposition list
$('#comp_list_id').hide();
$("#compReturn").load("capoCompReturn.php?w="+encodeURIComponent(item));
}
}
and then change the references in your HTML to include the namespace, e.g.
input box 1 (note the onkeyup)
<input id="country_id" type="text" placeholder="Enter a Part Number"
onsubmit="this.value=this.value.toUpperCase()" autocomplete="off" onkeyup="country.autocomplete()">
<ul id="country_list_id"></ul>
and then repeat for all the other references, including the one in the PHP code.
You may also want to check out Browserify which brings Node's require module syntax to the browser. Additionally, you might read up on closures and IIFE's in JS.

How to print JavaScript based on Ajax request?

Allow me to elaborate.
I have this Ajax script which is fetching for one thing. The refresh_on.
What does it do? It either returns 0 OR 1.
function startRefresh() {
setTimeout(startRefresh, 60000);
$.ajax({
url: 'refresh.php',
type: 'POST',
dataType: 'JSON',
data: {task: "reload"},
success: function(data) {
$.each(data, function(i, attr){
if (attr.refresh_on == 0) {
//this doesn't work
/*Write/return this in JavaScript:*/ line[1]="Offline.";
} else {
//this doesn't work
/*Write/return this in JavaScript:*/ line[1]="Online.";
};
})
}
});
}
If the ajax returns with refresh_on == 0 OR refresh_on == 1 - I want it to print its respective array item. It must be an array item.
</head>
<body>
<script type="text/javascript">
var line=new Array()
startRefresh();
//output either "line[1]=\"Offline.\""; or "line[1]=\"Online.\"";
</script>
</body>
This is the PHP file:
if (isset($_POST['task']) && $_POST['task'] == "reload") {
$stmt = $connection->prepare("SELECT refresh_on FROM refresh");
$stmt->execute();
$result = $stmt->get_result();
$encode = Array();
while ($row = $result->fetch_assoc()) {
$encode[] = $row;
}
echo json_encode($encode);
}
If it matters - this is the JSON response:
[{"refresh_on":1}]
Is there a way to insert/output/print the array item using the function?
Any help would be appreciated.
So there's a couple things that might be going on here, but to begin, you're wrapping your variable in a quote, so all that is happening is a string is being made and immediately being dropped to the floor. Let's start off by doing something like the following:
function startRefresh() {
setTimeout(startRefresh, 60000);
$.ajax({
url: 'refresh.php',
type: 'POST',
dataType: 'JSON',
data: {task: "reload"},
success: function(data) {
$.each(data, function(i, attr){
if (attr.refresh_on == 0) {
//this doesn't work
line[1] = "Offline.";
} else {
//this doesn't work
line[1]= "Online.";
};
})
}
});
}
Now, if I recall correctly, the ajax function is going to be calling your success callback, which is going to take over your local scope. I don't believe line is going to be accessible to that callback, so we should/could actually move that callback to its own function within a closure:
<script type="text/javascript">
(function() {
var line = [];
startRefresh();
function startRefresh() {
setTimeout(startRefresh, 60000);
$.ajax({
url: 'refresh.php',
type: 'POST',
dataType: 'JSON',
data: { task: "reload" },
success: refreshResponse
});
}
function refreshResponse(data) {
$.each(data, function(i, attr) {
if (attr.refresh_on == 0) {
line[1] = "Offline.";
} else {
line[1] = "Online.";
}
});
}
})();
</script>
We've wrapped that in a self executing function to give us some nice encapsulation to work with, and because line is in a function which refreshResponse is found, that variable should be accessible to it.
But we're not done yet!
For one, we could easily make that variable assignment a little easier, like so:
line[1] = (attr.refresh_on == 0) ? "Offline." : "Online.";
...and we're also going to want to triple up on that equality statement, just to avoid variable coercion:
line[1] = (attr.refresh_on === 0) ? "Offline." : "Online.";
Give that a shot and let's see where we're at.
Not sure what you are expecting "line[1]=\"Offline.\""; to do, but it's not going to do anything. Perhaps you mean: line[1]= "Offline";? Try putting this line of code there instead to test that it's working: console.log('Offline');
If the line is getting executed and you see the output in your console, you would just have to target some HTML element that you want to put the "Offline" string into, for instance:
<div id="status"></div>
<script>
....
var status = document.getElementById("status");
if (attr.refresh_on == 0) {
status.textContent = "Offline";
} else {
status.textContent = "Online";
};
....
</script>

How to save var value outside ajax success function?

I am trying to make some form validation functions. Here is what I have:
<script>
$(document).ready(function() {
var myObj = {};
$('#username').keyup(function () {
id = $(this).attr('id');
validateUsername(id);
});
function validateUsername(id){
var username = $("#"+id).val();
$.ajax({
url : "validate.php",
dataType: 'json',
data: 'action=usr_id&id=' + username,
type: "POST",
success: function(data) {
if (data.ok == true) {
$(myObj).data("username","ok");
} else {
$(myObj).data("username","no");
}
}
});
} // end validateusername function
$('#submit').click(function(){
if (myObj.username == "ok") {
alert("Username OK");
} else {
alert("Username BAD");
}
});
}); // end doc ready
So you can see, when a key is pressed in the textbox, it checks if it's valid. The "data.ok" comes back correctly. The problem is based on the response, I define $(myObj).username. For some reason, I can't get this value to work outside the validateusername function. When clicking the submit button, it has no idea what the value of $(myObj).username is.
I need to use something like this, because with multiple form fields on the page to validate, I can do something like:
if (myObj.username && myObj.password && myObj.email == "ok")
... to check all my form fields before submitting the form.
I know I must just be missing something basic.... any thoughts?
EDIT: SOLVED
All I had to do was change var myObj = {}; to myObj = {}; and it's working like a charm. I think I've been staring at this screen waaaaay too long!
You're not accessing the data that you stored properly. Access the username value this way:
$(myObj).data("username")
Resources:
Take a look at jQuery's .data() docs.
Very simple jsFiddle that shows how to properly set and retrieve data with jQuery's .data() method.
I would store the promise in that global variable and then bind an event to the done event within your submit button click.
$(document).ready(function() {
var myObj = false;
$('#username').keyup(function () {
id = $(this).attr('id');
validateUsername(id);
});
function validateUsername(id){
var username = $("#"+id).val();
myObj = $.ajax({
url : "validate.php",
dataType: 'json',
data: 'action=usr_id&id=' + username,
type: "POST",
success: function(data) {
$('#username').removeClass('valid invalid');
if (data.ok == true) {
$('#username').addClass('valid');
}
else {
$('#username').addClass('invalid');
}
}
});
} // end validateusername function
$('#submit').click(function(){
// if myObj is still equal to false, the username has
// not changed yet, therefore the ajax request hasn't
// been made
if (!myObj) {
alert("Username BAD");
}
// since a deferred object exists, add a callback to done
else {
myObj.done(function(data){
if (data.ok == true) {
alert("Username BAD");
}
else {
alert("Username OK");
}
});
}
});
}); // end doc ready
you may want to add some throttling to the keyup event though to prevent multiple ajax requests from being active at once.

Categories

Resources