Club PA 2.0 has arrived! If you'd like to access some extra PA content and help support the forums, check it out at patreon.com/ClubPA
The image size limit has been raised to 1mb! Anything larger than that should be linked to. This is a HARD limit, please do not abuse it.
Our new Indie Games subforum is now open for business in G&T. Go and check it out, you might land a code for a free game. If you're developing an indie game and want to post about it, follow these directions. If you don't, he'll break your legs! Hahaha! Seriously though.
Our rules have been updated and given their own forum. Go and look at them! They are nice, and there may be new ones that you didn't know about! Hooray for rules! Hooray for The System! Hooray for Conforming!

[Programming] Mirror, mirror, on the wall, show the git diff for them all

194969899100

Posts

  • SaerisSaeris Chronogestaltist Trinity, New MexicoRegistered User regular
    Does the other page have a keyup/keydown/keypress/input handler bound that's calling `event.preventDefault()`?

    Nlgya.png
  • EchoEcho Moderator mod
    Saeris wrote: »
    Does the other page have a keyup/keydown/keypress/input handler bound that's calling `event.preventDefault()`?

    It shouldn't, but I haven't looked everywhere yet.

    What happens is that I can't enter anything at all manually, and the datepicker instead instantly tells me the date is invalid. So something gets picked up.

    Echo wrote: »
    Let they who have not posted about their balls in the wrong thread cast the first stone.
  • IcyLiquidIcyLiquid Two Steaks Montreal, QuebecAdministrator, Vanilla Staff vanilla
    So, I have been building something. So far it has taken about 3 months all told, doing a little bit every few weekends or so. Much of the time has been spent either waiting for parts to be delivered, or sitting in the bath trying to think in 3 dimensions and plan the hardware.

    I present: Smart Mirror, IcyLiquid Edition
    kj3fltvyduhr.jpg
    alwb3fmq0pao.jpg

    The software consists of a web app built with ReactJS (https://facebook.github.io/react/), connected to a websocket server written in PHP using Ratchet (https://socketo.me). There is another socket client running code that catches events from a hardware motion sensor, so the mirror can gracefully "sleep" when no one is looking at it.

    The server has various "data sources" configured so it can poll regularly for updated weather, news, calendar events, traffic conditions, etc, and push those updates asynchronously to the UI via the websocket connection. I've built it so that multiple clients are supported, with the goal of expanding the number and type of connected devices in my house.

    Overall pretty happy with it, I'm going to hang it from the ceiling using some cement anchors/hooks and 2 steel cables.

    Heavily inspired (both in terms of concept, and the current iteration of the UI) by this Medium post https://medium.com/@maxbraun/my-bathroom-mirror-is-smarter-than-yours-94b21c6671ba#.9u7tc4s9d

    LD50NijaEchoLuvTheMonkeyecco the dolphinEtheaMvrckironsizideDelmainbowenFolken FanelMahnmutCarpymightyjongyozerzhulInfidelBarrakkethBaron DirigibleDisruptedCapitalisturahonkygavindeladmanbMr_RoseiTunesIsEvilthatassemblyguyJacobyGhotiskippydumptruckTofystedeth
  • LD50LD50 Registered User regular
    That is really cool.

    Mvrckecco the dolphinironsizideDelmainiTunesIsEvilGhoti
  • bowenbowen How you doin'? Registered User regular
    you should make it touch screen and implement a whole UI for it

    Ladies.
  • IcyLiquidIcyLiquid Two Steaks Montreal, QuebecAdministrator, Vanilla Staff vanilla
    That's planned for a smaller, dedicated wall mounted device.

    The mirror is intentionally non interactive because of finger smudges. I've thought about putting a gesture sensor on there, but I think I like it being purely an output device.

    bowenironsizide
  • bowenbowen How you doin'? Registered User regular
    I wonder if that material they use for track pads is transparent in some form? That'd make a great "touch screen" feel.

    Ladies.
  • LD50LD50 Registered User regular
    I'm disappointed in how few of you used the Shiny reaction for Icy's post.

  • bowenbowen How you doin'? Registered User regular
    Shiny is sarcastic I thought

    Ladies.
    Delmain
  • IcyLiquidIcyLiquid Two Steaks Montreal, QuebecAdministrator, Vanilla Staff vanilla
    Sad news: while fucking around with a custom power cable for the pi, I accidentally toasted it :(
    Happy news: ordered a replacement which will be more powerful :D

    bowen
  • LD50LD50 Registered User regular
    That didn't take long...

    DisruptedCapitalist
  • DisruptedCapitalistDisruptedCapitalist rugged, weathered Registered User regular
    Patent it!

  • IcyLiquidIcyLiquid Two Steaks Montreal, QuebecAdministrator, Vanilla Staff vanilla
    Patent it!

    I'm not the first, unfortunately. But I'm certainly having fun.

    DisruptedCapitalistbowen
  • amnesiasoftamnesiasoft Thick Creamy Furry Registered User regular
    IcyLiquid wrote: »
    Patent it!

    I'm not the first, unfortunately. But I'm certainly having fun.
    First to file!

    steam_sig.png
    EtheaDisruptedCapitalist
  • [Michael][Michael] Registered User regular
    Hah, the only two threads I read have very similar titles now

    Mahnmut
  • SaerisSaeris Chronogestaltist Trinity, New MexicoRegistered User regular
    edited May 2016
    Anyone have experience with Navigator.sendBeacon in Chrome? Every time I send a beacon, Chrome immediately cancels it. The request never even hits the server, according to the server logs. The method itself returns `true` indicating that the request was queued, but then the Chrome dev tools show the request with "(canceled)" status.

    Chrome's net-internals log says this:
    t=3105 [st=0] +REQUEST_ALIVE  [dt=3]
    t=3105 [st=0]    URL_REQUEST_DELEGATE  [dt=0]
    t=3105 [st=0]   +URL_REQUEST_START_JOB  [dt=3]
                     --> load_flags = 33024 (MAYBE_USER_GESTURE | VERIFY_EV_CERT)
                     --> method = "POST"
                     --> priority = "IDLE"
                     --> upload_id = "0"
                     --> url = "https://myserverhere/"
    t=3106 [st=1]      URL_REQUEST_DELEGATE  [dt=0]
    t=3106 [st=1]      HTTP_CACHE_CALLER_REQUEST_HEADERS
                       --> Cache-Control: max-age=0
                           Origin: https://myserverhere/
                           X-DevTools-Emulate-Network-Conditions-Client-Id: 807BC040-BCD8-445E-86EE-E0CE9BD90DB5
                           User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.63 Safari/537.36
                           Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryIwWYc69UmwMt6BQ8
                           Accept: */*
                           DNT: 1
                           Referer: https://myserverhere/
                           Accept-Encoding: gzip, deflate
                           Accept-Language: en-US,en;q=0.8
                           Cookie: [515 bytes were stripped]
                       --> line = ""
    t=3106 [st=1]      HTTP_CACHE_GET_BACKEND  [dt=0]
    t=3106 [st=1]      URL_REQUEST_DELEGATE  [dt=0]
    t=3106 [st=1]     +HTTP_STREAM_REQUEST  [dt=1]
    t=3106 [st=1]        HTTP_STREAM_REQUEST_STARTED_JOB
                         --> source_dependency = 181777 (HTTP_STREAM_JOB)
    t=3107 [st=2]        HTTP_STREAM_REQUEST_BOUND_TO_JOB
                         --> source_dependency = 181777 (HTTP_STREAM_JOB)
    t=3107 [st=2]     -HTTP_STREAM_REQUEST
    t=3108 [st=3]      CANCELLED
    t=3108 [st=3]   -URL_REQUEST_START_JOB
                     --> net_error = -3 (ERR_ABORTED)
    t=3108 [st=3]    URL_REQUEST_DELEGATE  [dt=0]
    t=3108 [st=3] -REQUEST_ALIVE
    

    No apparent reason, just "CANCELLED". At first I thought it was my adblocker, but I disabled that and I get the same behaviour. I've tried with an empty request body (no second argument), with just a plain empty FormData, and with a FormData that has some values. Nothing works.

    What the hell?

    Saeris on
    Nlgya.png
  • SaerisSaeris Chronogestaltist Trinity, New MexicoRegistered User regular
    True to standard programming thread form, I solved it almost immediately after posting that.

    Apparently Chrome will refuse to send beacons over HTTPS if the certificate can't be verified, even if the user has already accepted the cert for that domain. My development server doesn't have a real certificate, so, there's the problem. It works fine if I test it on HTTP instead.

    Nlgya.png
  • NogsNogs Crap, crap, mega crap. Registered User regular
    edited May 2016
    Gave a talk about React at my local javascript meetup last night!

    125+ people showed up and i talked for around 70 minutes, so i had a 5 minute break in there.

    Id done plenty of business meeting room talks and pitches in my life, but that was the first time id ever done anything like that to a crowd so big.

    If anyone is interested at all:

    Part 1
    Part 2

    No one threw trash at me, so im happy with it.

    Nogs on
    rotate.jpg
    PARKER, YOU'RE FIRED! <-- My comic book podcast! Satan look here!
    ecco the dolphinSaerisMvrckInfidelDisruptedCapitalisttemplewulfTofystedeth
  • EchoEcho Moderator mod
    I'm ever so slowly learning the ins and outs of this React code base.

    Current task is to implement a textbox that filters shown items. Managed to get the actual filter bit working, now I just need to figure out how to tell everything but the filtered items to go hide in a bush.

    Echo wrote: »
    Let they who have not posted about their balls in the wrong thread cast the first stone.
  • NogsNogs Crap, crap, mega crap. Registered User regular
    edited May 2016
    probably some structure like
    <ParentComponent>
       <TextBoxInputComponent />
       <FilteredListComponent />
    </ParentComponent>
    

    Maybe TextBoxInputComponent grabs the input, sends it up to ParentComponent, which then filters to get new list, which ParentComponent then sends the filtered list down as props to FilteredListComponent which renders however you want.

    Dont think of it as hiding away stuff, think of it as rendering a new list based off the new list provided by the filter

    Nogs on
    rotate.jpg
    PARKER, YOU'RE FIRED! <-- My comic book podcast! Satan look here!
  • zeenyzeeny Registered User regular
    edited May 2016
    What problem does the ParentComponent solve in the solution you propose?

    Edit: Uuuh, that came out like....aggressive. So....that wasn't the intention. I am genuinely asking.

    zeeny on
  • NogsNogs Crap, crap, mega crap. Registered User regular
    ParentComponent may not be needed if using something like Redux or whatever. Though, even Redux suggests using Container components to wrap display components.

    If you are using reacts setState on a component and want to use that state in some way to influence another component that isnt a child/grandchild/etc., you need to pass that state up to the nearest common parent. So then the parent can pass down to its children.

    Redux/Flux/MobX let you sidestep this process, but i just wanted to show the simplest possible way without using external libs.

    rotate.jpg
    PARKER, YOU'RE FIRED! <-- My comic book podcast! Satan look here!
  • SaerisSaeris Chronogestaltist Trinity, New MexicoRegistered User regular
    It decouples the other two. That's the main benefit I can see.

    Nlgya.png
  • zeenyzeeny Registered User regular
    Nogs wrote: »
    ParentComponent may not be needed if using something like Redux or whatever. Though, even Redux suggests using Container components to wrap display components.

    If you are using reacts setState on a component and want to use that state in some way to influence another component that isnt a child/grandchild/etc., you need to pass that state up to the nearest common parent. So then the parent can pass down to its children.

    Redux/Flux/MobX let you sidestep this process, but i just wanted to show the simplest possible way without using external libs.

    Thanks! I quiet agree with that!

  • EchoEcho Moderator mod
    I'll post some code when I get home, now it's almost weekend o'clock.

    Echo wrote: »
    Let they who have not posted about their balls in the wrong thread cast the first stone.
    ecco the dolphin
  • InfidelInfidel Heretic Registered User regular
    Also it makes you able to reuse the filter components if they receive a general list and filter to render.

    That might be reused in say three different places in your data structure and you can use the container to bind to the specific one. You can use the container to transform the data into something compatible as well

    OrokosPA.png
    Play D&D 4e? :: Check out Orokos and upload your Character Builder sheet! :: Orokos Dice Roller
    The PhalLounge :: Chat board for Critical Failures IRC! :: #CriticalFailures and #mafia on irc.slashnet.org
    Nogs
  • InfidelInfidel Heretic Registered User regular
    Now that I'm not on the phone, let me try to illustrate. This is useful (and imo should be used) even with Redux, I'll show why I think that.

    This is just off the top of my head so it's not necessarily complete code.
    class FilterInput extends React.Component {
      static propTypes = {
        onChange: PropTypes.func
      }
      ...
      render() {
        // show a text box and pass the value back up to the parent via the callback
      }
    }
    
    class FilteredGridView extends React.Component {
      static propTypes = {
        filterText: PropTypes.string,
        fields: PropTypes.arrayOf(PropTypes.string),
        data: PropTypes.arrayOf(PropTypes.object))
      }
      ...
      render() {
        // show a grid view with the specified fields and extract those fields from the data list
        // data is an array of rows, each row is an object and columns are extracted from the keys based on fields prop
        // if filterText is not null, only show rows that have a column that string matches filterText
      }
    }
    

    Two useful and reusable UI components. To use them, you make containers. Here's the redux way:
    @connect((state) => {
      return {
        users: state.users
      };
    })
    class UserList extends React.Component {
      render() {
        return <div>
          <FilterInput onChange={(filterText) => this.setState({filterText})}/>
          <FilteredGridView filterText={this.state.filterText} fields={['username', 'lastname', 'firstname', 'email']} data={this.props.users}/>
        </div>;
      }
    }
    

    Now I can control the presentation of those of course in the container, as I might want to rearrange how they look to make a nice reusable filterable panel for my UI. The container can represent that or if it gets more complicated I can use more intermediate components. The container is responsible for the data bindings, so handling the filterText state and binding into the data source (redux connect here).

    Need a new panel? No prob!
    @connect((state) => {
      return {
        logs: state.logs.latest.map((logtext) => ({text: logtext}))
      };
    })
    class LogEntries extends React.Component {
      render() {
        return <div>
          <FilterInput onChange={(filterText) => this.setState({filterText})}/>
          <FilteredGridView filterText={this.state.filterText} fields={['text']} data={this.props.logs}/>
        </div>;
      }
    }
    

    If you have a common UI arrangement for the gridview and the input field, you could pull that out into another component so that you don't repeat yourself, separating the data part that the container is responsible for from the arrangement of the UI and holding of the state for the text filter.

    A little contrived but this shows how you can have different sources of data in different kinds of formats (objects versus strings) and you can use the container to (a) specify the data source and (b) massage it into what you need.

    OrokosPA.png
    Play D&D 4e? :: Check out Orokos and upload your Character Builder sheet! :: Orokos Dice Roller
    The PhalLounge :: Chat board for Critical Failures IRC! :: #CriticalFailures and #mafia on irc.slashnet.org
    Echo
  • EchoEcho Moderator mod
    Yeah, that's totally different to how it works here. :rotate: Good read though, saving that for future analysis and experimentation. Not entirely impossible that I'll get a chance to rewrite stuff to use that method instead.

    Echo wrote: »
    Let they who have not posted about their balls in the wrong thread cast the first stone.
  • EchoEcho Moderator mod
    Aww yiss, got it working! (it still needs translation strings and some styling)

    ta0j0f4a0llg.png

    And then I can filter items:

    dnugxwe1vfhi.png

    Needs some more work to maybe hide categories that don't have any items displayed and maybe a button to clear the filter, but hey, it works!

    Echo wrote: »
    Let they who have not posted about their balls in the wrong thread cast the first stone.
    Delmain
  • EchoEcho Moderator mod
    22eoywdcq3sx.png

    blargh, Bootstrap.

    Echo wrote: »
    Let they who have not posted about their balls in the wrong thread cast the first stone.
    DisruptedCapitalist
  • SaerisSaeris Chronogestaltist Trinity, New MexicoRegistered User regular
    Hmm, "NO_TRANSLATION_FOUND", eh? On that topic...

    How do you folks in the modern JavaScript single-page app realm generally handle internationalization? Do you just put all of your translations in a big JSON file that gets bundled with the app? Do you use some other format? Do you serve the translations from a database? Do you have separate files per language? Do you leave them unbundled and then load only the one you need from the server? What do you use for keys in the map? Do you have a naming convention for those, or do you just use the literal English (or whatever native language) string as the key? Do you access the map as a plain object, or do you call a function to index it? What is your policy on translation reuse? If there's a "Confirm" button on two different dialogs, is that two different entries in the translation map, or are they shared? How do you work with your translators? Do you give them the location and context of each entry, or do they figure that out on their own? How do they contribute translations? Plain old email correspondence? Some kind of basic web interface? Direct source control access? When the user changes language preference, how do you handle that? Full page reload? If not, how do you enforce coding practices that avoid holding onto references to the previous language?

    I have spent years trying to find the right answers to questions like these. Internationalization seems to be a seriously under-represented topic in web apps. I have found no one -- no blog post, no forum thread, no errant tweet -- willing to offer a comprehensive prescription of How It Should Be Done And Why.

    Nlgya.png
  • djmitchelladjmitchella Registered User regular
    edited May 2016
    We use Ember, and a homebrew framework, depending on which bits of code we're in. Ember has ember-i18n, which lets you do Ember.I18n.t("savedialog.title") sort of thing in code, and {{t "printscreen.blah.message"}} in templates, and it then looks those up in a big JSON file which maps string name to string value as appropriate, and it loads those up at runtime from JSON files that get built in.

    Homebrew framework is different, we do FRAMEWORK.localize("English String Here") in code, and some sort of tagging I forget right now in HTML, and our framework then does the translation that way; again, one JSON file for each language, but this time the keys are the english strings. (so fallthrough is easier in the case where we don't have a translation yet).

    (in both cases you need to do a page reload to switch languages; we get the user's preferred language as best we can, which is frustratingly inconsistent depending on OS/browser, it turns out -- IE needs server-side support to detect it properly, Chrome has its own settings which override the OS, Safari uses the OS's preferences, etc)

    Now, where do the translations come from? The B+I folks have written scripts to extract the strings from code/HBS/HTML as necessary, the strings then get looked up against our corporate dictionary of Everything-We've-Ever-Had-Translated, and it then generates the appropriate dictionaries in the appropriate format at build time. (with gaps where we don't have a string translated yet).

    Strings that aren't translated go into a list of things-to-be-translated, every so often those go to the translators and when they come back, get re-added into the master dictionaries, and then the next time a build happens the per-language dictionaries that ship with the apps are more filled out. (I don't know how that bit of things work, sorry; I think it depends on which translation company we're using. I do know that we're meant to give context for the strings, though. "Grade" can mean "grade 1" -vs- "grade 10", or "A grade" -vs- "E grade", or even "20% grade" (if it's a hill), so we need to provide extra info as the translation varies.

    The other thing to remember is that if your UI has any sort of layout to think about, you need to remember to allow (roughly) twice as much room as you think you need, because English is a fairly concise language compared to others. In some cases it's worse -- in one particular bit of ui, "On" in English is best translated into Spanish as "Activado", which really did _not_ fit in the same space..

    (is this How It Should Be Done? I don't know if it's the best answer, but it works out pretty well for us; but we also have an internal webapp we use to manage getting strings edited by the documentation folks to match our corporate style guide for capitalisation, email -vs- e-mail, that sort of thing, so we have a pipeline for UI strings already in place and translation just sits at the far end of that.)

    djmitchella on
  • djmitchelladjmitchella Registered User regular
    Oh, and don't forget pluralization, which is its own exciting ball of fun; it's not just "1 cat" -vs- ">1 cats" as much as you might hope:

    http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html

  • LD50LD50 Registered User regular
    There's also languages with gendered articles too!
    "un gato" means one cat, but "una manzana" means one apple.

  • zeenyzeeny Registered User regular
    Do you guys want to do a fun exercise? You do a working js demo on as described in react, i do it in reagent. We compare code. I can pop in irc for that too;
    Saeris wrote: »
    Hmm, "NO_TRANSLATION_FOUND", eh? On that topic...

    How do you folks in the modern JavaScript single-page app realm generally handle internationalization? Do you just put all of your translations in a big JSON file that gets bundled with the app? Do you use some other format? Do you serve the translations from a database? Do you have separate files per language? Do you leave them unbundled and then load only the one you need from the server? What do you use for keys in the map? Do you have a naming convention for those, or do you just use the literal English (or whatever native language) string as the key? Do you access the map as a plain object, or do you call a function to index it? What is your policy on translation reuse? If there's a "Confirm" button on two different dialogs, is that two different entries in the translation map, or are they shared? How do you work with your translators? Do you give them the location and context of each entry, or do they figure that out on their own? How do they contribute translations? Plain old email correspondence? Some kind of basic web interface? Direct source control access? When the user changes language preference, how do you handle that? Full page reload? If not, how do you enforce coding practices that avoid holding onto references to the previous language?

    I have spent years trying to find the right answers to questions like these. Internationalization seems to be a seriously under-represented topic in web apps. I have found no one -- no blog post, no forum thread, no errant tweet -- willing to offer a comprehensive prescription of How It Should Be Done And Why.

    You use gettext adapter for whatever is your framework of choice(yes, there is one). You bundle translations as json during build process, if translators are tech saavy, poedit -> weblate(or other) -> git hook. If not, build an interface that does the same. It's a couple of day's work.

  • EchoEcho Moderator mod
    edited May 2016
    Okay, now I have a weird one I don't understand.

    I have a text input with onChange={this.onFilterChange}. I then did a debug log to check the input length, to see if the reset button should be enabled or not:
    onFilterChange: function(e) {
      var textFilter = e.target.value;
      console.log("filter length: " + textFilter.length);
      this.props.onChange(textFilter);
    }
    

    It logs 1, 2, 3 etc when I type, and count down again when I hit backspace. But it seems to not fire when I reach zero characters in the input field, it never logs "length: 0". What's up with that, and how should I do it to properly check it so I can toggle the reset button state?

    edit: further experimenting. Tried OnKeyPress/OnKeyDown, but then the counter is one step behind the state and shows 0 with one char in the field etc and doesn't fire at all on backspace.

    Echo on
    Echo wrote: »
    Let they who have not posted about their balls in the wrong thread cast the first stone.
  • EchoEcho Moderator mod
    Not entirely sure what I did, but I got it working now. I can probably still clean this up a bit.

    I have the textFilter state in the component for ease of access, but it's actually this.props.internalState.searchState that gets set on the onChange call, and handles the actual filtering.
    var SidebarSearchField = React.createClass({
      getInitialState: function() {
        return ({textFilter: "", resetIsDisabled: true})
      },
      componentWillMount: function() {
        // Set searchState value from initial state so it's not undefined when mounting
        this.props.onChange(this.state.textFilter);
      },
      onFilterChange: function(e) {
        var textFilter = e.target.value;
        this.setState({textFilter: textFilter});
    
        if (textFilter.length > 0) {
          this.setState({resetIsDisabled: false});
        } else {
          this.setState({resetIsDisabled: true});
        }
    
        this.props.onChange(textFilter);
      },
      resetFilter: function() {
        this.setState({textFilter: "", resetIsDisabled: true});
        this.props.onChange("");
      },
      render: function() {
        return (
          <div className="group-tile sidebar-search-field input-group input-group-sm">
            <input type="text" className="form-control"
              placeholder={this.props.getTranslation("SidebarFilterPlaceholder")}
              value={this.state.textFilter}
              onChange={this.onFilterChange}/>
            <span className="input-group-btn">
              <button className="btn" type="button"
                onClick={this.resetFilter}
                disabled={this.state.resetIsDisabled}>
                <span className="glyphicon glyphicon-eye-open"></span>
              </button>
            </span>
          </div>
        )
      }
    });
    

    Echo wrote: »
    Let they who have not posted about their balls in the wrong thread cast the first stone.
  • SaerisSaeris Chronogestaltist Trinity, New MexicoRegistered User regular
    edited May 2016
    I'm not sure how React maps the onChange callback to the native DOM, but generally you'd use the input event for exactly that purpose. It has the advantage of firing only when the input actually changes, not just on any key press.

    Saeris on
    Nlgya.png
  • EchoEcho Moderator mod
    edited May 2016
    React docs:
    For <input> and <textarea>, onChange supersedes — and should generally be used instead of — the DOM's built-in oninput event handler.

    So that's what I went with.

    edit: though I do call the prop "onChange" in the component as well, guess I'll rename that to avoid confusion.

    Echo on
    Echo wrote: »
    Let they who have not posted about their balls in the wrong thread cast the first stone.
  • InfidelInfidel Heretic Registered User regular
    onChange is the correct thing to use, it would fire on the final backspace.

    You will have some problems though with your onFilterChange, since you call setState more than once in the tick. This can lead to lost updates since depending on ticks and the event loop, you'll overwrite/lose the change.

    What you could do is make it like:
    this.setState({textFilter: textFilter, resetIsDisabled: textFilter.length === 0});
    

    but what I would do is get rid of resetIsDisabled, because it is entirely derived from state you already have. Try to keep only the state that is necessary. You would just write this in your render:
    disabled={this.state.textFilter.length === 0}
    

    OrokosPA.png
    Play D&D 4e? :: Check out Orokos and upload your Character Builder sheet! :: Orokos Dice Roller
    The PhalLounge :: Chat board for Critical Failures IRC! :: #CriticalFailures and #mafia on irc.slashnet.org
    Nogs
This discussion has been closed.