Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
5TonsOfFlax
Aug 31, 2001
The problem is that you've attached your event handler to all the matching elements that exist when that line runs, not to any that may exist in the future.

What you need to do is attach the event handler to the document body and look at the classname there. I think jQuery has a syntax just for this http://api.jquery.com/on/

Adbot
ADBOT LOVES YOU

Video Nasty
Jun 17, 2003

100 degrees Calcium posted:

I wish I could say that was it, but this was actually my failure in re-typing the code when I should have copied-pasted. I don't even know why I did that.

I think that was the only typo I created here, but just in case I've edited my post with the code actually copied.

I'm really flailing with this one, I don't even have a theory at this point, except that possibly adding the element by including the HTML in a string and simply appending the string to a cell somehow doesn't count as adding an element as far as re-draw is concerned. But forcing the re-draw isn't working and I don't really know a better/cleaner way.

The post above me is correct, but here's a Pen proving it out: https://codepen.io/anon/pen/KmejWm

You need to use $(document).on() to handle changes to the DOM like adding an input and maintaining live functionality.

edit: shows how long ago I picked up jQuery. That article is from 2015 and I swear the previous method was to always attach to the document and then label the target as the second argument before entering an anonymous function.

Video Nasty fucked around with this message at 01:59 on May 16, 2017

100 degrees Calcium
Jan 23, 2011



Awesome. This was exactly the trick. Thank you all so much.

reversefungi
Nov 27, 2003

Master of the high hat!
You don't have to attach it to document, you can just attach it to the parent container.

https://learn.jquery.com/events/event-delegation/

100 degrees Calcium
Jan 23, 2011



poo poo. I'm embarrassed to have messed up something so basic, but I'm learning a lot of good poo poo here.

smackfu
Jun 7, 2004

My least favorite JavaScript "typo" is when something wants you to make a variable either camel case or dash case depending on the context. So even though your JavaScript and your HTML have the same variable name, it's not correct and acts like your variable doesn't even exist.

N.Z.'s Champion
Jun 8, 2003

Yam Slacker
afaik the plain JS way of doing $(document).on('change', selector, callback) can be done with matches,

code:
function on(eventType, selector, callback) {
  document.addEventListener(
    eventType,
    function(e){
        if (e.target.matches(selector)) {
          callback(e) // or maybe callback.bind(this)(e)
        }
    },
    false
  );
}
usage:
code:
on('change', 'p input[type=file]', function(e){ ... } );

The Fool
Oct 16, 2003


Need help wrapping my head around promises.

I need to make 3 api calls, and then do stuff to the results. I need wait until all three calls have returned.

Currently what I have working is a total mess of cascading callbacks and I want to fix it.

Using Node and request.

Any links, or a quick run down?

Video Nasty
Jun 17, 2003

I recommend this article for in-depth understanding of promises: http://www.mattgreer.org/articles/promises-in-wicked-detail/
MDN also has a good explanation without getting too detailed.

Dr. Poz
Sep 8, 2003

Dr. Poz just diagnosed you with a serious case of being a pussy. Now get back out there and hit them till you can't remember your kid's name.

Pillbug
The link from Video Nasty is a REALLY good resource. This blog post is also really helpful for exploring the nuances and pitfalls that people run into in the wild: https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html

Lumpy
Apr 26, 2002

La! La! La! Laaaa!



College Slice

The Fool posted:

Need help wrapping my head around promises.

I need to make 3 api calls, and then do stuff to the results. I need wait until all three calls have returned.

Currently what I have working is a total mess of cascading callbacks and I want to fix it.

Using Node and request.

Any links, or a quick run down?

Assuming your requests thing returns a Promise:

code:
const p1 = request(....);
const p2 = request(....);
const p3 = request(....);

Promise.all([p1,p2,p3]).then(function (results) {

   // all your requests are done and results
   // is an array of each request's 
  // result in the order you
  // passed them in

});

Skandranon
Sep 6, 2008
fucking stupid, dont listen to me

The Fool posted:

Need help wrapping my head around promises.

I need to make 3 api calls, and then do stuff to the results. I need wait until all three calls have returned.

Currently what I have working is a total mess of cascading callbacks and I want to fix it.

Using Node and request.

Any links, or a quick run down?

Quick answer is, if you are using ES6 promises, is to use Promise.all([p1, p2, p3]).then( (allThreeResponsesArray) => { // do stuff to results } );, where p1 p2 and p3 are your API calls.

Edit: bah, beaten.

The Fool
Oct 16, 2003


Based on what I've read,

I have this working code:

code:
request(options, function (error, res, body) {
  context.res = body;
  context.done();
});
then using request-promise-native:
code:
request(options).then(function (error, res, body) {
  context.res = body;
  context.done();
});
should accomplish the same thing.

However, I'm just getting timeouts when testing with the promise.

This is in and Azure functions app, for what it's worth. Am I making a stupid mistake, or is something else going on?

edit: it times out because context.done() is never being called, which means .then() is never being called. which means?

The Fool fucked around with this message at 23:07 on May 16, 2017

Video Nasty
Jun 17, 2003

The Fool posted:

code:
Promise( request(options) ).then(function (error, res, body) {
  context.res = body;
  context.done();
});

You weren't using a Promise for your then call.
nevermind me, this is patently stupid.

Video Nasty fucked around with this message at 23:16 on May 16, 2017

The Fool
Oct 16, 2003


Video Nasty posted:

You weren't using a Promise for your then call.

I was under the impression that 'request-promise-native' did that for me?

Video Nasty
Jun 17, 2003

The Fool posted:

I was under the impression that 'request-promise-native' did that for me?

Hrm, maybe it isn't wrong.
npm shows that you're clearly still supposed to call Promise to resolve before chaining the next function step. Not certain if this is the same package?
https://www.npmjs.com/package/react-promise

e: Either way, you need to govern the state of the promise resolution to delegate what fires next, so I do think you should wrap it in a Promise call.

The Fool
Oct 16, 2003


Video Nasty posted:

Hrm, maybe it isn't wrong.
npm shows that you're clearly still supposed to call Promise to resolve before chaining the next function step. Not certain if this is the same package?
https://www.npmjs.com/package/react-promise

e: Either way, you need to govern the state of the promise resolution to delegate what fires next, so I do think you should wrap it in a Promise call.

Going to mess with it, but the examples linked from https://www.npmjs.com/package/request-promise-native don't do any wrapping.

Video Nasty
Jun 17, 2003

The Fool posted:

Going to mess with it, but the examples linked from https://www.npmjs.com/package/request-promise-native don't do any wrapping.

You're absolutely right. Ignore me, I looked up the wrong information.

The Fool
Oct 16, 2003


Continuing my saga:
code:
p1 = Promise(request(options));
Gives: TypeError: undefined is not a promise

idkwtf

edit: this is with the normal requestjs module

Blinkz0rz
May 27, 2001

MY CONTEMPT FOR MY OWN EMPLOYEES IS ONLY MATCHED BY MY LOVE FOR TOM BRADY'S SWEATY MAGA BALLS

The Fool posted:

Continuing my saga:
code:

p1 = Promise(request(options));

Gives: TypeError: undefined is not a promise

idkwtf

edit: this is with the normal requestjs module

That's not how Promises work.

If you're using request (as in not rp) your promise code should look like this

code:

const p1 = new Promise((resolve, reject) => {
  request(options, (err, res, body) => {
    if (err) {
      reject(err);
    }

    resolve(body);
  });
});

p1 then becomes a Promise and you can either chain it with then() and catch() or else pass it to Promise.all() to coordinate request completion.

Do more reading about Promises before you try to get around it by using Promise-based implementations without understanding what it's doing under the hood.

The Fool
Oct 16, 2003


Blinkz0rz posted:

That's not how Promises work.

If you're using request (as in not rp) your promise code should look like this
*snip*

I haven't been able to get rp to work either.

quote:

p1 then becomes a Promise and you can either chain it with then() and catch() or else pass it to Promise.all() to coordinate request completion.

I get that. I've read a million examples of this, and I should have been able to just use rp to do this:
code:
p1 = rp(options1);
p2 = rp(options2);
p3 = rp(options3);

Promise.all([p1,p2,p3]).then( function(results) {
  context.res = results;
  context.done;
});
The associated requests work fine in cascading callbacks, but when I try to do them as promises, .then() is never called and my function just times out.
Same thing happens if I try to do this with only one API call. eg: rp(options).then(function(results) {});

quote:

Do more reading about Promises before you try to get around it by using Promise-based implementations without understanding what it's doing under the hood.

Thanks dad.

edit: vvv- ha, yeah, just a typo for that post

The Fool fucked around with this message at 01:08 on May 17, 2017

Kekekela
Oct 28, 2004

The Fool posted:

code:
p1 = rp(options1);
p2 = rp(options2);
p3 = rp(options3);

Promise.all([p1,p2,p3).then( function(results) {
  context.res = results;
  context.done;
});

I'm guessing this is just an error made while posting your code, but just in case: you're missing a closing bracket in Promise.all([p1,p2,p3)

ROFLburger
Jan 12, 2006

The Fool posted:

then using request-promise-native:
code:
request(options).then(function (error, res, body) {
  context.res = body;
  context.done();
});

If you're not getting a 'then is not a function' error then you're probably not handling some exception that's being thrown. Try either a
code:
request(options).then(successHandler).catch(errorHandler) 
or a second handler passed to
code:
.then(successHandler, errorHandler)

The Fool
Oct 16, 2003


Just having .catch() present solved my timeout problem on the single API call test. It's not even getting called. Let's see if it works with Promise.all()

edit: all works now. Using bluebird instead of native promises because that's what I had it set to when the tests started working.


Thanks for everyone's help, would have taken way longer and been way more frustrating without it

The Fool fucked around with this message at 01:53 on May 17, 2017

LP0 ON FIRE
Jan 25, 2006

beep boop
I have a table row click event listeners that are driving me crazy. If I click the text inside the row's columns, the event does not trigger first click. It will the 2nd. I thought it might have to do with event bubbling or capturing, but I tried capturing with no luck. I'm afraid it might have to do something Polymer messing with things. Any other ideas of what could cause this? Does it have to do something with focus?

e: I don't know what I'm talking about with "focus". You can only focus on input elements. :(

LP0 ON FIRE fucked around with this message at 21:45 on May 17, 2017

necrotic
Aug 2, 2005
I owe my brother big time for this!
It might be polymer. This very simple fiddle works on every click from the start: https://jsfiddle.net/834mxrn8/

LP0 ON FIRE
Jan 25, 2006

beep boop

necrotic posted:

It might be polymer. This very simple fiddle works on every click from the start: https://jsfiddle.net/834mxrn8/

I tried the same thing in jsfiddle. I also attempted to capture any target clicked first click on the text inside the table row on the original page I'm having the problem. It logs nothing first click.

code:
$(document).click(function(event) {
    var text = $(event.target).text();
    console.log(text);
});
What would prevent something like this in html in the first place?

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



LP0 ON FIRE posted:

I tried the same thing in jsfiddle. I also attempted to capture any target clicked first click on the text inside the table row on the original page I'm having the problem. It logs nothing first click.

code:
$(document).click(function(event) {
    var text = $(event.target).text();
    console.log(text);
});
What would prevent something like this in html in the first place?

Something would have to stop the event from propagating. Here's how to find what's doing it http://stackoverflow.com/a/10213800/301807

Dominoes
Sep 20, 2007

Hey dudes. I'm trying to make an NPM package from some code that works around a limitation of another package; posted about this earlier. Would anyone mind skimming my build files (webpack.cfg and package.json) to see if there's anything I'm missing? The component works properly when placing the src index.tsx file in with my other files and importing, but webpack can't find my module when trying to import through npm_modules.

Dominoes fucked around with this message at 17:52 on May 18, 2017

necrotic
Aug 2, 2005
I owe my brother big time for this!
You have to publish the compiled code I believe. Node/NPM don't know anything about typescript. http://stackoverflow.com/questions/30928253/writing-npm-modules-in-typescript

edit: Just looked at your package.json, looks like you are publishing that way. Shoulda looked first, sorry.

LP0 ON FIRE
Jan 25, 2006

beep boop

Munkeymon posted:

Something would have to stop the event from propagating. Here's how to find what's doing it http://stackoverflow.com/a/10213800/301807

Thanks for the info. I found that a click event is never registered the first time if the user clicks the text in the td as explained above, but a mouseup event is made. I figured out a work around by checking if the event.target of the mouseup event is a td and the parent has a data-dialog attribute for the popup that is supposed to get triggered.

Add this fix to your coding horrors:

code:
var mouseClicked = false;
    
$(document).mouseup(function(event) {

    /*

    if first mouse up and element is td
        check if parent is has attribute data-dialog
            click event target

    */

    if(mouseClicked === false){

        mouseClicked = true;

        if($(event.target).is('td')){

            var par = $(event.target).parent();

            var attr = $(par).attr('data-dialog');

            if (typeof attr !== typeof undefined && attr !== false) {
                $(par).click();
            }

        }

    }

});

PierreTheMime
Dec 9, 2004

Hero of hormagaunts everywhere!
Buglord
What's the simplest way to disable and "grey out" a button while a process occurs? I'm cobbling together a rudimentary frontend for an API as a demo and for some reason none of the things I've googled for seem to work. The rest of my awful code is working about as well as can be expected. I just know as soon as I show someone the first thing they'll do is hammer the button dozens of times while they wait for a large GET response. As an example, here's one of my functions:

code:
function getworkflowinfo() {
    	var parser = new DOMParser();
    	var client = document.getElementById("client");
    	var level = document.getElementById("level");
    	var object = document.getElementById("object");
    	var jobinfo = document.getElementById("jobinfo");
    	var getinfo = document.getElementById("getinfo");
    	getinfo.value = "Processing...";
    	getinfo.disabled = true;
    	jobinfo.value = 'Waiting on response from server for object ' + object.value.toUpperCase() + '...';
    	var url = "(web address)/" + client.value + "/" + level.value.toUpperCase() + "/" + object.value.toUpperCase() + "/";
    	xmlhttp.open('GET', url, true);
    	xmlhttp.send(null);
    	xmlhttp.onreadystatechange = function () {
    		if (xmlhttp.readyState == 4) {
    			if (xmlhttp.status == 200) {
    				var xmlDoc = parser.parseFromString(xmlhttp.responseText, "text/xml");
    				jobinfo.value = '';
    				var info = xmlDoc.getElementsByTagName("*");
    				for (var i = 1; i < info.length; i++) {
    					if (info[i].childNodes.length == 1) {
    						if (['name'].indexOf(info[i].nodeName) > -1 && i > 1) {
    							jobinfo.value += ("\n" + info[i].nodeName.capitalize() + ':' + info[i].firstChild.nodeValue + "\n");
    						} else {
    							jobinfo.value += (info[i].nodeName.capitalize() + ': ' + info[i].firstChild.nodeValue + "\n");
    						}
    					}
    				}
    			} else {
    				jobinfo.value = ("Error processing request for object " + object.value.toUpperCase() + "!\n");
    				jobinfo.value += ("Please check client/Level information and ensure object exists.");
    			}
    		}
    	};
    	getinfo.disabled = false;
    	getinfo.value = "Get Info";
    }
 
As this is my first dabbling of JS I'd be interest on any input into how terrible the above code is.

PierreTheMime fucked around with this message at 20:25 on May 18, 2017

Dominoes
Sep 20, 2007

Your code for disabling and enabling the button is fine. I suspect your xmlhttp request is acting asynchronously. You could place a console.log() statement at your button disable, at your button re-enable, and at the end of (but inside) your request function. If the re-enable one fires before the request one, this is your problem.

Dominoes fucked around with this message at 20:36 on May 18, 2017

ddiddles
Oct 21, 2008

Roses are red, violets are blue, I'm a schizophrenic and so am I

PierreTheMime posted:

What's the simplest way to disable and "grey out" a button while a process occurs? I'm cobbling together a rudimentary frontend for an API as a demo and for some reason none of the things I've googled for seem to work. The rest of my awful code is working about as well as can be expected. I just know as soon as I show someone the first thing they'll do is hammer the button dozens of times while they wait for a large GET response. As an example, here's one of my functions:

code:
function getworkflowinfo() {
    	var parser = new DOMParser();
    	var client = document.getElementById("client");
    	var level = document.getElementById("level");
    	var object = document.getElementById("object");
    	var jobinfo = document.getElementById("jobinfo");
    	var getinfo = document.getElementById("getinfo");
    	getinfo.value = "Processing...";
    	getinfo.disabled = true;
    	jobinfo.value = 'Waiting on response from server for object ' + object.value.toUpperCase() + '...';
    	var url = "(web address)/" + client.value + "/" + level.value.toUpperCase() + "/" + object.value.toUpperCase() + "/";
    	xmlhttp.open('GET', url, true);
    	xmlhttp.send(null);
    	xmlhttp.onreadystatechange = function () {
    		if (xmlhttp.readyState == 4) {
    			if (xmlhttp.status == 200) {
    				var xmlDoc = parser.parseFromString(xmlhttp.responseText, "text/xml");
    				jobinfo.value = '';
    				var info = xmlDoc.getElementsByTagName("*");
    				for (var i = 1; i < info.length; i++) {
    					if (info[i].childNodes.length == 1) {
    						if (['name'].indexOf(info[i].nodeName) > -1 && i > 1) {
    							jobinfo.value += ("\n" + info[i].nodeName.capitalize() + ':' + info[i].firstChild.nodeValue + "\n");
    						} else {
    							jobinfo.value += (info[i].nodeName.capitalize() + ': ' + info[i].firstChild.nodeValue + "\n");
    						}
    					}
    				}
    			} else {
    				jobinfo.value = ("Error processing request for object " + object.value.toUpperCase() + "!\n");
    				jobinfo.value += ("Please check client/Level information and ensure object exists.");
    			}
    		}
    	};
    	getinfo.disabled = false;
    	getinfo.value = "Get Info";
    }
 
As this is my first dabbling of JS I'd be interest on any input into how terrible the above code is.

You need to put your getinfo.disabled = false; line inside the onreadystatechange method if you want it to enable the button depending on the AJAX call. As it stands now it's going to disable, start the async ajax call and then keep on executing your code, which the next line is getinfo.disabled = false.

ddiddles fucked around with this message at 20:41 on May 18, 2017

PierreTheMime
Dec 9, 2004

Hero of hormagaunts everywhere!
Buglord

ddiddles posted:

You need to put your getinfo.disabled = false; line inside the onreadystatechange method if you want it to enable the button depending on the AJAX call. As it stands now it's going to disable, start the async ajax call and then keep on executing your code, which the next line is getinfo.disabled = false.

That did it, thanks!

Roadie
Jun 30, 2013
Here's a question at the intersection of Typescript and Immutable.js, in case anybody is crazy enough to know the answer.

I have a Record-extending class Tom, with the attributes jones, ofFinland, and andJerry. I get in an arbitrary string, whichTom. How do I define a Typescript type guard function such that this:

code:
const isATom = (whichTom: string, tomInstance: Tom): boolean {
  // some kind of type guard shenanigans here?
  return tomInstance.has(whichTom)
}

if (isATom(whichTom, tomInstance)) {
  return tomInstance.get(whichTom)
}
doesn't give me a Argument of type "string" is not assignable to parameter of type '"jones" | "ofFinland" | "andJerry"'. Typescript error?

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



Roadie posted:

Here's a question at the intersection of Typescript and Immutable.js, in case anybody is crazy enough to know the answer.

I have a Record-extending class Tom, with the attributes jones, ofFinland, and andJerry. I get in an arbitrary string, whichTom. How do I define a Typescript type guard function such that this:

code:
const isATom = (whichTom: string, tomInstance: Tom): boolean {
  // some kind of type guard shenanigans here?
  return tomInstance.has(whichTom)
}

if (isATom(whichTom, tomInstance)) {
  return tomInstance.get(whichTom)
}
doesn't give me a Argument of type "string" is not assignable to parameter of type '"jones" | "ofFinland" | "andJerry"'. Typescript error?

Are jones, ofFinland, and andJerry all the same type?

Sedro
Dec 31, 2008
I think you can do tomInstance.has(<keyof Tom>whichTom)

PierreTheMime
Dec 9, 2004

Hero of hormagaunts everywhere!
Buglord
Is there a generally accepted way to do single signon/LDAP authentication for single-page apps? I basically want to valid that the user is a valid employee and pass their user id in my REST request for logging afterward. I'm building a super-simple site for some reporting features and I'd like to keep it all in one file if possible, but if it must use other stuff I guess I can get to learning that as well.

Adbot
ADBOT LOVES YOU

Vulture Culture
Jul 14, 2003

I was never enjoying it. I only eat it for the nutrients.

PierreTheMime posted:

Is there a generally accepted way to do single signon/LDAP authentication for single-page apps? I basically want to valid that the user is a valid employee and pass their user id in my REST request for logging afterward. I'm building a super-simple site for some reporting features and I'd like to keep it all in one file if possible, but if it must use other stuff I guess I can get to learning that as well.
Same way you do it with any traditional app: you send an auth request against the server, the server generates a secret session key for the user, and you pass that session key with subsequent requests to authenticate them. If you want to get fancy, you can do asymmetric key auth with an ephemeral keypair and actually sign your requests to authenticate them post-login, but that's probably way overkill if you're already using HTTPS.

If you want to keep it extremely bare-bones, you can just do HTTP Basic against an LDAP backend. Nginx or Apache or whatever will give this to you out of the box as a reverse proxy.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply