0

I have this code snippet from MDN

I then added a bit of my own code to attach a jQuery click event to a paragraph.

Maybe it is best to show the example:

 function Person(first, last, age, gender, interests) {
      this.name = {
        'first': first,
        'last' : last
      };
      this.age = age;
      this.gen = gender;
      this.int = interests;
      this.nationality = "English";
      this.bio = function() {
        alert(this.name.first + ' ' + this.name.last + ' is ' + this.age + ' years old. He likes ' + this.int[0] + ' and ' + this.int[1] + '.');
      };
      this.greeting = function() {
        alert('Hi! I\'m ' + this.name.first + '.');
      };
      this.tt = function() {
        alert('Hi! I\'m ' + this.gen + '.');
      };  
    
      this.init= function() {
        $("p").click(function(){
         alert('Hi!'); //works fine
          alert('Hi! I\'m ' + this.name.first + '.');//obj.html:34 Uncaught TypeError: Cannot read property 'first' of undefined
         }); 
      };
    
      this.init(); //Bind to the P tag using jQuery click event
    
    }
    var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
    console.log(Person);
    person1.bio();
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    
    <p>My first paragraph.</p>
 

So when I click on the P element I get the alert Hi! followed by the uncaught error message.

How do I get the second alert to read, "Hi! I'm Bob"

Deepu Reghunath
  • 4,992
  • 1
  • 22
  • 37
JimF
  • 125
  • 1
  • 7

5 Answers5

2

If you wish to retain the reference to the Person object, then you need to bind the jQuery callback function with the thisBinding.

this.init= function() {
     $("p").click(function(){
      alert('Hi!'); //works fine
      alert('Hi! I\'m ' + this.name.first + '.');
     }.bind(this));//binding this prevents the error
  };
Travis J
  • 77,009
  • 39
  • 185
  • 250
2

There are a few ways to solve your problem. this keyword in JavaScript is tricky. The core of your problem is that the this is not what you think it is. See How does the "this" keyword work? for more details.

1) Cache the this into a variable in pervious scope.

this.init = function () {
  var self = this;
  $("p").click(function () {
    alert('Hi!');
    alert('Hi! I\'m ' + self.name.first + '.');
  });
};

2) bind this into the function that's being invoked

this.init = function () {
  var handleClick = function () {
    alert('Hi!');
    alert('Hi! I\'m ' + self.name.first + '.');
  };
  handleClick = handleClick.bind(this);
  $("p").click(handleClick);
}; 
Steven
  • 2,118
  • 1
  • 20
  • 22
  • Travis and Steven - Thanks to both! The reason I selected Stevens answer is it is easier for me to add var self=this; – JimF Mar 28 '18 at 08:38
  • 1
    @JimF - That's fine, perhaps this post will be informational for you: https://stackoverflow.com/a/24173441/1026459 – Travis J Mar 28 '18 at 08:49
  • Thanks for the link Travis. After a while it dawned on me $("p").click(function(){ did not have for example this.name defined due to a scope issue. – JimF Mar 28 '18 at 09:21
0

You need to bind this to the anonymous function you passed in jquery click() function.

function Person(first, last, age, gender, interests) {
  this.name = {
    'first': first,
    'last' : last
  };
  this.age = age;
  this.gen = gender;
  this.int = interests;
  this.nationality = "English";
  this.bio = function() {
    alert(this.name.first + ' ' + this.name.last + ' is ' + this.age + ' years old. He likes ' + this.int[0] + ' and ' + this.int[1] + '.');
  };
  this.greeting = function() {
    alert('Hi! I\'m ' + this.name.first + '.');
  };
  this.tt = function() {
    alert('Hi! I\'m ' + this.gen + '.');
  };  

  this.init= function() {
     $("p").click(function(){
      alert('Hi!'); //works fine
      alert('Hi! I\'m ' + this.name.first + '.');
     }.bind(this)); 
  };

  this.init(); //Bind to the P tag using jQuery click event

}
var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
console.log(Person);
person1.bio();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>My first paragraph.</p>
Deepu Reghunath
  • 4,992
  • 1
  • 22
  • 37
atiq1589
  • 1,823
  • 14
  • 23
0

Another way to do this is to just declare a variable name outside the jquery function and use it inside the function

this.init = function() {
    var name = this.name;
    $("p").click(function(){
        alert('Hi!');
        alert('Hi! I\'m ' + name.first + '.');
    }); 
};
Dumisani
  • 2,742
  • 24
  • 37
0

Be careful when using this for variables. This, in your code refers to thePersoninstance. As soon as you create a new functionthisno longer references thePersonfunction, but thethis.initfunction, thusPerson` no longer exists in this context.

Rather user var name... when using variables, then you will be able to reference it in another context or function:

<!DOCTYPE html>
    <html>
    <head>
    <title>Page Title</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    </head>
    <body>
    <p>My first paragraph.</p>
    <script>
    function Person(first, last, age, gender, interests) {
      var name = {
        'first': first,
        'last' : last
      };
      var age = age;
      var gen = gender;
      var int = interests;
      var nationality = "English";
      this.bio = function() {
        alert(name.first + ' ' + name.last + ' is ' + age + ' years old. He likes ' + int[0] + ' and ' + int[1] + '.');
      };
      this.greeting = function() {
        alert('Hi! I\'m ' + name.first + '.');
      };
      this.tt = function() {
        alert('Hi! I\'m ' + gen + '.');
      };  
    
      this.init= function() {
        $("p").click(function(){
         alert('Hi!'); //works fine
          alert('Hi! I\'m ' + name.first + '.');//obj.html:34 Uncaught TypeError: Cannot read property 'first' of undefined
         }); 
      };
    
      this.init(); //Bind to the P tag using jQuery click event
    
    }
    var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
    console.log(Person);
    person1.bio();
    </script> 
    </body>
    </html>