2

for some reason when I run npm start and I hit the browser, I am getting this stack trace with this error.

TypeError: $.ajax is not a function

at getLocationFromIp (G:\Github\Expressjs\nodetest1\routes\index.js:13:7)
at G:\Github\Expressjs\nodetest1\routes\index.js:24:14

Would someone be able to tell me why? Here is my code. Thanks!

var express = require('express');
var router = express.Router();
var externalip = require('external-ip');
var $ = require('jquery');

getLocationFromIp = function() {
    $.ajax({
       url:"freegeoip.net/json/",
       type: "GET",
       data: null,
       dataType: "json",
       success: function(){console.log("success!")}
     });
 }

router.get('/', function(req, res) {
    var ip = getLocationFromIp();
    res.render('index', { 'ip' : "hi"});
});
Patrick Guan
  • 37
  • 1
  • 3

2 Answers2

6

See the documentation:

For jQuery to work in Node, a window with a document is required. Since no such window exists natively in Node, one can be mocked by tools such as jsdom. This can be useful for testing purposes.

var externalip = require('external-ip');

require("jsdom").env("", function(err, window) {
    if (err) {
        console.error(err);
        return;
    }
    var $ = require("jquery")(window);

     function getLocationFromIp() {
        $.ajax({
            url: "freegeoip.net/json/",
            type: "GET",
            data: null,
            dataType: "json",
            success: function() {
                console.log("success!")
            },
            error: function() {
                console.log("error", arguments[2])
            }
        });
    }
    var ip = getLocationFromIp();
    console.log(ip);
});

You'd probably be better off using an HTTP library designed to work with Node from the outset, such such as request.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • that means i would have to run npm install jsdom as well? and how would this fire? onload? – Patrick Guan Mar 26 '16 at 17:22
  • Yes, you'd need to install jsdom in order to use that. `onload` makes no sense in this context, nothing is loading. You'd just to set up jQuery before you started the server. As I said, you'd be better off using a different library to make HTTP requests, it would be much simpler. – Quentin Mar 26 '16 at 17:24
  • If its the case that its missing a document, then would one solution be to just simply move this ajax call to the client side instead? – Patrick Guan Mar 26 '16 at 17:24
  • 1
    You'd probably run straight into the same origin policy. – Quentin Mar 26 '16 at 17:26
  • I got this working in TypeScript too. I posted the gist here: https://gist.github.com/ctaggart/87fea160bea50c11a36954bd4dc865c5 – Cameron Taggart Dec 09 '16 at 17:44
  • .env() is deprecated since v10. The new method is explained in [this answer](https://stackoverflow.com/a/48561379/5958842). – DecimalTurn Aug 11 '20 at 21:59
  • https://www.npmjs.com/package/request - This package has been deprecated Author message: request has been deprecated, see https://github.com/request/request/issues/3142 – Nufosmatic Dec 29 '20 at 17:25
2

If you are using jquery to just make a http request, you can probably use the http or request node module to do that instead.

var express = require('express');
var router = express.Router();
var externalip = require('external-ip');
var http    = require('http');

getLocationFromIp = function(done) {
  var options = {
    host: "freegeoip.net",
    port: 80,
    path: "/json"
  };

  var request = http.get(options, function(response) {
    var result = "";
    var responseCode = response.statusCode;

    response.on('data', function(data) {
      result += data;
    });

    response.on('end', function() {
      if(responseCode >= 400)
        return done(result, null);
      else
        return done(false, JSON.parse(result));
    });
  });

  request.on("error", function(error){
    return done("Error handling error", null);
  });

  request.end();
}

router.get('/', function(req, res) {
    var ip = getLocationFromIp(function(error, ip){
      res.render('index', { 'ip' : "hi"});
    });
});
Phagun Baya
  • 2,127
  • 1
  • 18
  • 27