Custom attr() method cannot be given a different name - javascript

I have the following perfectly working code (written by someone else). The problem is that if I simply rename the attr method, I get an error. For example, I rename the method to attrx and get this error:
TypeError: arg.attrx is not a function
Here is the working code:
function Action(name) {
this.attr = function(n) {
if (n=="name") {
return "action";
}
},
this.val = function() {
return name;
};
}
Action.prototype.toString = function() {
return "&" + this.attr("name") + "=" + this.val();
}
When a user triggers an event, the following function is called:
function serializeElements() {
var result = "";
for(var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
result += (arg.attr("name") + "=" + arg.val() + "&");
}
return result;
}
Here is the identical code above but it has the attr method renamed to attrx:
function Action(name) {
this.attrx = function(n) {
if (n=="name") {
return "action";
}
},
this.val = function() {
return name;
};
}
Action.prototype.toString = function() {
return "&" + this.attrx("name") + "=" + this.val();
}
function serializeElements() {
var result = "";
for(var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
result += (arg.attrx("name") + "=" + arg.val() + "&");
}
return result;
}
I cannot figure out the reason that the code does not work (see error at top of message) after I rename the method to attrx or anything else for that matter.
Note: The web page does include jQuery, but I don't think that is what causes the problem.
Here is the code used to call serializeElements:
function addStatesListener() {
$("#states").on("change", function(e) {
var form = $(this.form);
var url = form.attr("action");
var type = form.attr("method");
// pass 1) jQuery 'country' and 'state' objects and 2) a query string fragment, e.g.: '&action=change_state'
var data = serializeElements($("#countries"), $("#states"), new Action("change_state"));
e.preventDefault();
$.ajax({
url: url,
type: type,
data: data,
dataType: "html", // The type of data that you're expecting back from the server
success: function(result) {
$("#cities").html(result); // list of all cities, e.g.: <option value="Albany"</option>
}
});
});
}

The proper answer to your question is want already catch #dinesh, you are passing 3 arguments to your function, and only the third is an Action with the .attrx method you changed.
Considering you are working on jquery objects, and if you want to clean your code, you could use .serialize() method instead of calling the couple .attr() and .val().
.serialize() is the jquery method to serialize form objects.
So you can change your code as follow:
function Action(name) {
this.serialize=function() {
return 'name='+encodeURI(name);
}
}
And then your function serializeElements:
function serializeElements() {
var args = Array.prototype.slice.call(arguments);
return args.reduce(function(a, b){
if (a) return a.serialize() + '&' + b.serialize();
if (b) return b.serialize();
});
}
Then you can call it so:
var data = serializeElements($("#countries,#states"), new Action("change_state"));
As you see, you could put form elements in a comma separated list on jquery selector.
That's it.

Related

Javascript not recognizing self.function when inside onclick event

I have a Javascript file that I added to. It's for a twitter plugin, and I'm adding a filter function.
This is my script (the relevant parts):
;(function ( $, window, document, undefined ) {
var pluginName = "twitterFeed",
defaults = {
username: null,
webservice_url: "/services/Scope/Country_United_States_Internet/TwitterService.svc/DoTwitterSearch",
num_tweets: 3
};
// The actual plugin constructor
function Plugin( element, options ) {
this.element = element;
this.options = $.extend( {}, defaults, options );
this._defaults = defaults;
this._name = pluginName;
this.init();
}
Plugin.prototype = {
init: function() {
//if username is unknown
if(this.options.username == null) {
// do nothing
try{console.log('twitter username not found')}catch(err){};
return false;
}
// Get the tweets to display
this.getTweets();
$(".twitter-search input").on("change", function () {
var filters = this.formatFilters($(this).val());
this.getTweets(filters);
});
},
formatFilters : function(filterString) {
var hashtags = filterString.split(" ");
var hashtagString = "";
for (var i = 0; i < hashtags.length; i++) {
var hashtag = hashtags[i];
hashtag = hashtag.replace(",", "");
if (hashtag[0] !== "#") {
hashtag = "#" + hashtag;
}
hashtagString += " " + hashtag;
}
return hashtagString;
},
getTweets : function(filters){
var self = this;
var query = "from:" + self.options.username;
if (filters) {
query += filters;
}
var post_data = JSON.stringify(
{
"PageSize" : self.options.num_tweets,
"TwitterQuery" : query
}
);
$.ajax({
type: "POST", // Change to POST for development environment
url: this.options.webservice_url,
data: post_data,
contentType: "application/json; charset=utf-8",
dataType: "json",
timeout:2000,
success: function(data) {
// render the tweets
self.renderTweets(data.ContentItems);
},
error: function(error, type){
try{console.log(type);}catch(err){}
}
});
},
I added the $(".twitter-search input") on change event (in init) and I added the formatFilters() function. However, in the onchange function, I get the error "this.formatFilters() is not defined". I tried removed this but still got "formatFilters() is not defined.
Remember that this inside of an event handler means whatever HTML element the event was activated on.
Instead, you need to keep track of the actual Plugin object, not the HTML element.
var self = this;
$(".twitter-search input").on("change", function () {
var filters = self.formatFilters($(this).val());
self.getTweets(filters);
});
The problem you are experiencing is with function scope. When you refer to this in the event handler it points to the callback scope and not the scope of your formatFilters function.
To fix it - In the init function add var self = this; on the first line and then change the call to use self.formatFilters instead of this.formatFilters

Function as parameter in Jquery Ajax

Is it possible to put a function into a parameter for Jquery Ajax like below. dataType and data are given as functions. dataType returns a value of JSON if the returntype is JSON and text if isJson is false.
dataVal and dataVar are arrays containing the parameter names and values used to construct the data paramater. The result of the data: function would be a string as:
{dataVar[0]:dataVal[0],dataVar[1]:dataVal[1],.....,}
I'm getting an error when I try this, so, just wanted to know if this method was possible.
function getAjaxResponse(page, isJson, dataVar, dataVal, dfd) {
$.ajax(page, {
type: 'POST',
dataType: function () {
if (isJson == true) {
return "JSON";
} else {
return "text";
}
},
data: function () {
var dataString = '{';
for (var i = 0; i < dataVar.length; i++) {
dataString = dataString + dataVar[i] + ':' + dataVal[i] + ',';
}
console.log(dataString);
return dataString + '}';
},
success: function (res) {
dfd.resolve(res);
}
});
}
Edit
As per answers and comments, made the changes. The updated function is as below. This works:
function getAjaxResponse(page, isJson, dataVar, dataVal, dfd) {
$.ajax(page, {
type: 'POST',
dataType: isJson ? "JSON" : "text",
data: function () {
var dataString ="";
for (var i = 0; i < dataVar.length; i++) {
if (i == dataVar.length - 1) {
dataString = dataString + dataVar[i] + '=' + dataVal[i];
} else {
dataString = dataString + dataVar[i] + '=' + dataVal[i] + ',';
}
}
return dataString;
}(),
success: function (res) {
dfd.resolve(res);
}
});
}
And my original question is answered. But apparently, data is not getting accepted.
The return value of the data function is just treated as the parameter name and jquery just adds a : to the end of the request like so:
{dataVar[0]:dataVal[0]}:
So, my server is unable to pick up on the proper paramater name.
From the manual:
data
Type: PlainObject or String
So no.
Call the function. Use the return value.
data: function () { ... }();
// ^^ call the function
Not that way. But it will work with a little change:
(function () {
if (isJson == true) {
return "JSON";
} else {
return "text";
}
})()
That should work. You just call the function immidiately after you created it. This way, dataType is a String and the script will work.
Same with data. Also use the (function(){})()-notation here
jquery just adds a : to the end of the request like so:
{dataVar[0]:dataVal[0]}:
No, your devtools display does. However, as you're data string does not contain a = sign, and you send the content as application/x-www-form-urlencoded, the whole body is interpreted as if it was a parameter name.
For sending JSON, you should:
use contentType: "application/json"
use data: JSON.stringify(_.object(dataVar, dataVal))1
to ensure valid JSON is sent with the correct header (and correctly recognised as such at the server).
1: _.object is the object function from Underscore.js which does exactly what you want, but you can use an IEFE as well:
JSON.stringify(function(p,v){var d={};for(var i=0;i<p.length;i++)d[p[i]]=v[i];return d;}(dataVar, dataVal))
You need to call the function with parenthesis like below:
function func1(){
//func1 code in here
}
function func2(func1){
//func2 code in here
//call func1 like this:
func1();
}
So, you can use like this:
data: function () {
//your stuff her
}(); // which mean you are having data()

Identify the caller (or how pass parameter) of a callback (JSON) function in JavaScript

When i request
BASE_URL + 'json/valueone?callback=fnCallBack0'
the response from server is treated in a callback function. This function receives (ASYNCHRONOUS) data (JSON format) but do not include the initial parameter "valueone"
var BASE_URL = ...
function fnCallBack(data){
if (data != null) {
// HERE...I NEED ID <====================
// arguments.callee.caller <==================== dont work
console.log('information', data);
}
}
// onclick callback function.
function OnClick(info, tab) {
var arrH = ['valueone', 'valuetwo'];
arrH.forEach(function(value) {
var scrCallBack = document.createElement('script');
scrCallBack.src = BASE_URL + 'json/' + value + '?callback=fnCallBack';
//BASE_URL + 'json/one?callback=fnCallBack0';
document.body.appendChild(scrCallBack);
});
My solution is to create an intermediate function correlative name (fnCallBack0, fnCallBack1, ...), a global array, and a counter. Works fine, but this is not OOP, is a fudge.
var BASE_URL = ...
//global array
var arrH = [];
var fnCallBack0 = function(data){
fnCallBack(data, '0');
}
var fnCallBack1 = function(data){
fnCallBack(data, '1');
}
function fnCallBack(data, id){
if (data != null) {
console.log('information', data + arrH[id]);
}
}
// onclick callback function.
function OnClick(info, tab) {
var i = 0;
arrH = ['valueone', 'valuetwo'];
arrH.forEach(function(value) {
var scrCallBack = document.createElement('script');
scrCallBack.src = BASE_URL + 'json/' + value + '?callback=fnCallBack' + (i++).toString();
//BASE_URL + 'json/one?callback=fnCallBack0';
document.body.appendChild(scrCallBack);
});
chrome.contextMenus.create({
title: '%s',
contexts: ["selection"],
onclick: function(info) {console.log(info.selectionText)}
});
var idConsole = chrome.contextMenus.create({
title: 'console',
contexts: ["selection"],
onclick: OnClick
});
I tried with inject function as code in html page, but i receeived "inline security error", and a lot of similar questions.
Please, NO AJAX and no jQuery.
This is my first post and my first chrome extension
Thanks in advanced.
I don't see how anything of this has to do with OOP, but a solution would be to just create the callback function dynamically so that you can use a closure to pass the correct data:
function fnCallBack(data, value){
if (data != null) {
console.log('information', data + value);
}
}
// onclick callback function.
function OnClick(info, tab) {
['valueone', 'valuetwo'].forEach(function(value, index) {
// unique function name
var functionName = 'fnCallback' + index + Date.now();
window[functionName] = function(data) {
fnCallBack(data, value);
delete window[functionName]; // clean up
};
var scrCallBack = document.createElement('script');
scrCallBack.src = BASE_URL + 'json/' + value + '?callback=' + functionName;
document.body.appendChild(scrCallBack);
});
}

JavaScript Revealing Module Pattern Variable Scope

I have an issue where I can't get to a variable inside a function:
EDIT
I forgot to add that I am setting this workerPage.grid = $("#grid").data("kendoGrid"); on the jQuery $(function(){});
I can't use claimsGird variable inside the save function, I have to referenec it by workerPage.grid. Not the other variables like viewModel work fine. Here is the snippet:
save = function () {
saif.kendoGridUtils.addModifiedDataItems(
viewModel.CompanionClaims.Updated,
viewModel.CompanionClaims.Added,
$("#grid").data("kendoGrid").dataSource.data()
);
$.ajax({
url: $("#contentForm").attr("action"),
data: JSON.stringify(viewModel),
type: "POST",
contentType: "application/json"
}).success(function (data) {
//syncs viewModel with changes in model
$.extend(viewModel, kendo.observable(data));
//rebinds the grid data source
claimsGrid.dataSource.data(viewModel.CompanionClaims.Rows);
Here is the full script:
var workerPage = (function () {
var viewModel = kendo.observable(#Html.Raw(Json.Encode(Model))),
claimsGrid = null,
deleteFirm = function (firmModel) {
firmModel.Name = "";
firmModel.AttorneyName = "";
firmModel.Address.Line1 = "";
firmModel.Address.Line2 = "";
firmModel.Address.City = "";
firmModel.Address.State = "OR";
firmModel.Address.ZipCode = "";
firmModel.Address.PlusFourCode = "";
firmModel.PhoneNumber = "";
firmModel.FaxNumber = "";
firmModel.ContactName = "";
},
bind = function () {
kendo.bind($("#main-content"), viewModel);
},
save = function () {
saif.kendoGridUtils.addModifiedDataItems(
viewModel.CompanionClaims.Updated,
viewModel.CompanionClaims.Added,
$("#grid").data("kendoGrid").dataSource.data()
);
$.ajax({
url: $("#contentForm").attr("action"),
data: JSON.stringify(viewModel),
type: "POST",
contentType: "application/json"
}).success(function (data) {
//syncs viewModel with changes in model
$.extend(viewModel, kendo.observable(data));
//rebinds the grid data source
claimsGrid.dataSource.data(viewModel.CompanionClaims.Rows);
//rebinds view elements to view model so changes are visible
//kendo.bind($("#main-content"), viewModel);
bind();
// Errors and Warnings
var results = messageUtils.parseMessages(
viewModel.Messages.Errors,
viewModel.Messages.Informationals,
viewModel.Messages.Warnings
);
var errs = $("#errors").html(results.errorMessages);
$("#informationals").html(results.informationalMessages);
$("#warnings").html(results.warningMessages);
$.each(saif.kendoGridUtils.processErrors(viewModel.CompanionClaims.Rows), function (i, message) {
errs.html(errs.html() + message + "<br>");
});
// End Errors and Warnings
});
},
deleteRow = function () {
var row = claimsGrid.select(),
rowDataItem = claimsGrid.dataItem(row),
rowIndex = $(row).index(),
addedItemIndex = $.inArray(rowDataItem, viewModel.CompanionClaims.Added);
//add to Deleted if not new
if (addedItemIndex == -1 && $.inArray(rowDataItem, viewModel.CompanionClaims.Rows) != -1) {
viewModel.CompanionClaims.Deleted.push(rowDataItem);
}
//remove from Added if exists
if (addedItemIndex != -1) {
viewModel.CompanionClaims.Added.splice(addedItemIndex, 1);
}
claimsGrid.removeRow(row);
//select the next row, eg. if you delete row 2, select the row that took that rows poisition after it was deleted.
claimsGrid.select(claimsGrid.tbody.find(">tr:eq(" + rowIndex + ")"));
};
return {
bind: bind,
deleteFirm: deleteFirm,
deleteRow: deleteRow,
grid: claimsGrid,
save: save,
viewModel: viewModel
};
}());
The issue is that claimsGrid is never set to anything other than null. And setting workerPage.grid won't change the value of claimsGrid -- it's not a pointer, just a copy.
You'll instead have to use a getter/setter. With newer browsers/engines, that can be done with get and set:
// ...
return {
// ...
get grid() {
return claimsGrid;
},
set grid(grid) {
claimsGrid = grid;
},
// ...
};
You can also define grid as a function:
// ...
function getOrSetGrid(grid) {
if (typeof newGrid === 'undefined') {
return claimsGrid;
} else {
claimsGrid = grid;
}
}
return {
// ...,
grid: getOrSetGrid,
// ...
};
// ...
// rather than: workerPage.grid = ...;
workerPage.grid(...);
Or split it into getGrid and setGrid functions.
Scope in javascript works differently than other languages like Java or C#. In your case claimsGrid is not in scope for the save function. Does this help? http://coding.smashingmagazine.com/2009/08/01/what-you-need-to-know-about-javascript-scope/

Getting null value to controller's action passing from javascript using jquery

What I tried in my project is like passing checkbox's selected value as a comma separated string to json of my controller.. but i'm not getting a value to the json action.. it shows null over there.
How can I do this? Please help me
function getIds(checkList)
{
var idList = new Array();
var loopCounter = 0;
jQuery("input[name=" + checkList + "]:checked").each
(
function()
{
idList[loopCounter] = jQuery(this).val();
loopCounter += 1;
}
);
alert(idList);
jQuery.getJSON("/Photos/CheckForIdsJson", { idList: idList });
}
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult CheckForIdsJson(Int32[] idList)
{
JsonResult result = new JsonResult();
result.Data = idList;
return result;
}
You can have a look at this post : AJAX Post of JavaScript String Array to JsonResult as List<string> Always Returns Null? or this one : Send list/array as parameter with jQuery getJson . It seems that you have to indicate traditional: true in your ajax call.
Use this in your script :
var did ='',
$("#tbl").find("input:checkbox").each(function (i) {
if (this.checked == true) {
did += $(this).val() + ",";
}
});
alert(did);
if (did == "") {
alert("Please Select");
return;
}

Categories

Resources