Javascript and JQuery "this" scope errors - javascript

A sample bit of code:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
<div id="myinfo">info</div>
<input id="clickme" type="button" value="click here to display info"/>
<script type="text/javascript">
function Fighter() {
this.name = "Kenny"; // fighters name
this.hp = 10; // fighters hp
this.getHP = function() {
return this.hp;
}
this.getName = function() {
return this.name;
}
this.initUpdateButton = function(button_id) {
$(button_id).click(function() {
$("#myinfo").html("Name: "+this.getName()+"<br/>HP:"+this.getHP());
// this.getName is undefined
});
}
};
var me = new Fighter();
alert("Name: "+me.getName()+"<br/>HP:"+me.getHP()); // works properly
me.initUpdateButton("#clickme"); // bind it to some ID
</script>
Simply put, given a JavaScript class with JQuery mixed in, I understand that on the callback for JQuery functions (i.e. $.click()), that this is referring to the object that was clicked and Not the Class or root function(). so this.getName() and this.getHP() don't work.
But what is the best way to get around this problem?
I saw some similar posts but they weren't of use to me so sorry if this is a repost and thanks in advance.

this.initUpdateButton = function(button_id) {
var self = this;
$(button_id).click(function() {
$("#myinfo").html("Name: "+self.getName()+"<br/>HP:"+self.getHP());
});
}

Related

Error : javascript Function Add to class dynamically

I am new to web development.
Today I learn about classes(function) in javascript. I got an error how to call dynamically added method.
My Code :
<head runat="server">
<title></title>
<script type="text/javascript" language="javascript">
function MyMethod(name, fn) {
var str = "MyFunction1.prototype." + name + "= fn;";
eval(str);
}
function MyFunction1() {
MyMethod("start", function () { return "hi"; });
var abc = this.start(); //gives error
}
</script>
</head>
<body>
<form id="form1" runat="server" >
<div>
<input type="button" value="Click" onclick="MyFunction1()"/>
</div>
</form>
Here when I click the input button then not able to call the dynamically added function
How can i call the start() function that i added here.
Please Help me.
Thanks in Advance.
this in MyFunction1 referes to the global object in that case(for browsers it is window) , because you call MyFunction1 as function and you don't create an object by using new MyFunction1().
Another thing to be noted. You should not use eval when it is possible to do it without eval.
You can do the same thing using:
function MyMethod(name, fn) {
MyFunction1.prototype[name] = fn;
}
Using eval prevents you from using optimization tools or tools to validate your code. At least most of these tools don't take eval into account or even give a warning about that you are using it.
Try adding "new" before your onclick call to MyFunction1, creating an instance of it.
It reseolved I did
Hi , It resolved .Thanks for the gret help i did :
function fnOnload() {
MyMethod("start", function () { return "hi"; });
}
function MyMethod(name, fn) {
var str = "MyFunction1.prototype." + name + "= fn;";
eval(str);
}
function MyFunction1() {
}
function MyFunction2()
{
var aa = new MyFunction1();
var answee = aa.start();
}
and in click of button i callled function MyFunction2()
without changing your code you can do as follow , but I say it would be helpful if you read about invocations types and about this variable.
function MyMethod(name, fn) {
MyFunction1.prototype[name]= fn;
return MyFunction1.prototype;
}
function MyFunction1() {
var myPrototype= MyMethod("start", function () { return "hi"; });
var returnValue = myPrototype.start();
console.log(returnValue);
}

Javascript not declaring variables

i'm new to JavaScript i have this script and i want to declare a variable on a if but on document.write , returns nothing what am i doing wrong ?
<head>
<script>
(function () {
setInterval(function () {
var NetworkStatus = document.getElementById("status"),
isOnline = navigator.onLine;
if (isOnline) {
NetworkStatus.innerHTML = "Online";
NetworkStatus.className = "online";
var person="John Doe";
} else {
NetworkStatus.innerHTML = "Offline";
NetworkStatus.className = "offline";
var person="Santa Claus";
}
}, 100);
})();
</script>
</head>
<body>
<h1 id="status"></h1>
<script>
document.write(person + "<br>");
</script>
</body>
It's just all wrong, why use an IIFE and a timeout when all you have to do is add the script in the tag at the end of the DOM.
Also, you're setting the innerHTML of the element, and using document.write, which will overwrite the document ?
<head>
<title>I messed up</title>
</head>
<body>
<h1 id="status"></h1>
<script>
var NetworkStatus = document.getElementById("status"),
isOnline = navigator.onLine;
if (isOnline) {
var person = "John Doe";
NetworkStatus.innerHTML = "Online " + person;
NetworkStatus.className = "online";
} else {
var person = "Santa Claus";
NetworkStatus.innerHTML = "Offline " + person;
NetworkStatus.className = "offline";
}
</script>
</body>
You are in IIFE. which creates its own scope
And that's where it stays
Do this :
window.person="Santa Claus";
Instead of what you're doing.
var sets the scope of the variable to the function it is declared within. You are trying to document.write it from outside that function, so it is out of scope and inaccessible.
Use window.person instead of var person.
The function executes after 100ms which means the person variable has no value when the page loads.

Setting a knockout observable using sammy for routing

I have a SPA using knockout JS for data binding and sammy for routing. I have a deck of cards that I am trying to have a dynamic routing to. My problem is that it doesn't work when I try to set a knockout observable from the routing function in sammy.
My HTML, where I try to bind the name of the deck, looks like this:
<!-- Create Deck -->
<div id="createDeck" class="page" style="display:none;">
<input type="text" class="form-control" placeholder="Untitled Deck..." data-bind="value: $root.deck.name" />
</div>
<script type="text/javascript" src="lib/jquery-1.9.1.js"></script>
<script type="text/javascript" src="lib/knockout-2.3.0.js"></script>
<script type="text/javascript" src="lib/bootstrap.min.js"></script>
<script type="text/javascript" src="lib/sammy.js"></script>
<script type="text/javascript" src="js/Models/Deck.js"></script>
<script type="text/javascript" src="js/Models/Card.js"></script>
<script type="text/javascript" src="js/ViewModels/DeckViewModel.js"></script>
<script type="text/javascript" src="js/ViewModels/CardViewModel.js"></script>
<script type="text/javascript" src="js/routing.js"></script>
The Deck.js and DeckViewModel.js looks like below
function Deck(deckid, name, cards) {
var self = this;
self.id = deckid;
self.name = name;
self.cards = cards;
}
function DeckViewModel(deck, cards) {
var self = this;
self.deck = ko.observable(deck);
self.cards = ko.observableArray(cards);
self.goToCard = function (card) { location.hash = card.deckid + '/' + card.id };
}
// Bind
var element = $('#createDeck')[0];
var deckView = new DeckViewModel(null, null);
ko.applyBindings(deckView, element);
Finally, in my routing I try to create a new Deck, like this:
// Client-side routes
(function ($) {
var app = $.sammy('#content', function () {
this.get('#deck/:id', function (context) {
showPage("createDeck", ": Create Deck");
console.log(this.params.id);
deckView.deck = new Deck(1, "test", null);
console.log(deckView.deck);
});
});
$(function () {
app.run('#/');
});
})(jQuery);
function showPage(pageID, subHeader) {
// Hide all pages
$(".page").hide();
// Show the given page
$("#" + pageID).show();
// change the sub header
$("#subHeader").text(subHeader);
}
As you can see, I'm trying to create a test deck with the name 'test', but the binding <input type="text" class="form-control" placeholder="Untitled Deck..." data-bind="value: $root.deck.name" /> seems to bind the letter 'c'.
I'm at a loss, please help.
I tried to make a jsfiddle to demonstrate my problem
In your code the value assignment is not correct unless you are using Knockout-es5 plugin. here is the correct code
var app = $.sammy('#content', function () {
this.get('#deck/:id', function (context) {
showPage("createDeck", ": Create Deck");
console.log(this.params.id);
deckView.deck(new Deck(1, "test", null));
console.log(deckView.deck());
});
});
The way I've done this before is to define my Sammy() routes within the ViewModel. Shorter example for brevity:
(function($) {
function ViewModel() {
var self = this;
self.deckId = ko.observable(null);
Sammy(function() {
this.get('#/deck/:deckId', function(context) {
self.deckId(this.params.deckId);
});
});
}
$(function() {
ko.applyBindings(new ViewModel());
});
})(jQuery);
That way you can access your observables, etc, via self.

window.onload Javascript, with functions that receives parameter?

I have this function:
<script type="text/javascript">
var car = document.getElementById("Carros").value;
window.onload = ChangeValue(car);
function ChangeValue(str)
{
....
}
See that ChangeValue(str) receives a parameter, how may I make it start in the pageLoad?
using javascript ! The parameter I pass is a <select id="" onChange="ChangeValue(this.value)">
window.onload = function () {
var car = document.getElementById("Carros").value;
ChangeValue(car);
}

Namespace schema for JavaScript

I come from the world of Java. In Java there are packages, for example, "com.mycompany.billing" and classes that are inside the package, for example, "BillProcessor". The company in which I work is starting a new project and I need to decide on a good namespace schema. I'm thinking of projecting how it's done in Java to JavaScript, for example, having a namespace "com.mycompany.billing" and a class that's in a file like "BillProcessor.js". In addition, unit testing is vital so I need such a structure that is easy to unit test.
Can somebody suggest a good approach?
I think that I came up with a good solution, please advise. As an example I'll make a billing page. There are 4 files:
${root}/billing.html - contains an input box for the name on credit card
${root}/js/com/mycompany/common/common.js - initializes logging and error handling
${root}/js/com/mycompany/common/Url.js - class that is used to perform an AJAX call
${root}/js/com/mycompany/aproject/billing.js - initializes things on the billing page
So for example, common.js contains:
var com_mycompany_common_common = function() {
function log(message) {
console.log((new Date()) + ': ' + message);
}
function init() {
window.onerror = function(message) {
log('Unhandled error: ' + message);
}
}
return {
log: log,
init: init
}
} ();
$(document).ready(function() {
try {
com_mycompany_common_common.init();
} catch (e) {
console.log('Error during initialization: ' + e);
}
});
Url.js:
function com_mycompany_common_Url(url) {
this.url = url;
}
com_mycompany_common_Url.prototype.addParameter(name, value) {
this.url += '?' + name + '=' + value;
}
com_mycompany_common_Url.prototype.ajax() {
com_mycompany_common_common.log('Send ajax to: ' + this.url);
}
billing.js
var com_mycompany_aproject_billing = function() {
function init() {
$('#submitButton').click(function() {
Url url = new com_mycompany_common_Url('http://bla.com/process/billing');
var creditCardName = $('#ccName').val();
url.addParameter('name', creditCardName);
url.ajax();
}
}
return {init: init};
} ();
$(document).ready(function() {
try {
com_mycompany_aproject_billing.init();
} catch (e) {
console.log('Error during initialization: ' + e);
}
});
billing.html
<!DOCTYPE html>
<html>
<head>
<title>Billing</title>
</head>
<body>
Enter name on credit card: <input type="text" id="ccName" /><br><br>
<button id="submitButton">Submit Payment</button>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript" src="js/com/mycompany/common/common.js"></script>
<script type="text/javascript" src="js/com/mycompany/common/Url.js"></script>
<script type="text/javascript" src="js/com/mycompany/aproject/billing.js"></script>
</body>
</html>
Most of the time people use the Object Literal pattern to achieve name spacing in JavaScript.
More info: http://msdn.microsoft.com/en-us/scriptjunkie/gg578608
You can "nest" namespaces like so:
var MyCompany = MyCompany || {};
MyCompany.Billing = MyCompany.Billing || {};
// etc...
Another ScriptJunkie article that covers some namespacing stuff: http://msdn.microsoft.com/en-us/scriptjunkie/hh377172.aspx
I'M POSTING THIS QUESTION ON https://codereview.stackexchange.com/questions/8393/approach-to-organizing-javascript-for-an-html-page MAYBE I'LL GET ANSWERS THERE.

Categories

Resources