locked
App closes when calling function

    Question

  • Hello,

    I am developing a APP for windows 8.1 and I got in a weird situation.

    I have a HTML form and I am willing to make it save the information (through JavaScript function) on blur of the input. See HTML of the input:

    <input type="text" name="shipper_shop_name" id="shipper_shop_name" value="" onblur="_saveSettingsForm(this);">

    Whenever the input is unselected, the APP closes, and Visual Basic stops to emulate APP. I verified and whenever I use:

    <input type="text" name="shipper_shop_name" id="shipper_shop_name" value="" onblur="console.log('aaaa');">

    It shows in the JavaScript console: "aaaa".

    More information about APP

    • The form (HTML file) is loaded from a different path through XMLHttpRequest()
    • I am using the template "Grid App"
    • The function _saveSettingsForm() is loaded in the "ItemDetail.js" file, inside: WinJS.UI.Pages.define("/pages/itemDetail/itemDetail.html", { ready: function (element, options) {

    Thank you for the help.

    Best Regards,
    Vitor de Souza


    Wednesday, December 04, 2013 4:45 PM

Answers

  • Once you have form.html loaded in the DOM, e.g. through setting an innerHTML property, you can use document.getElementById or document.querySelector to access any of those loaded elements. Once you have the element you want, you can call its addEventListener.
    Friday, December 06, 2013 5:59 PM

All replies

  • What's happening is what you're assigning to the events here are not functions, but return values.

    Assigning to an onblur or any other on* attribute requires that you assign a function object, so that the function is called when the event happens.

    In your case, you're assigning a bit of code that is executed (hence the console output) and then the return value is assigned to the event handler. I suspect that the return values in both cases are "undefined" which means an exception is thrown when the event occurs, as you cannot call "undefined" as a function.

    Typically, declarative assignments to event attributes just specify the name of a function defined elsewhere. For example, if you create a handler in your JS like this:

    function blurHandler (e) {
        _saveSettingsForm();
    }

    Then you'd wire it up like this (shortening your markup for convenience):

    <input type="text" id="shipper_shop_name" onblur="blurHandler">

    You can also just inline the function wrapper like this:

    <input type="text" id="shipper_shop_name" onblur="function () { _saveSettingsForm(); }">

    Note that I've omitted the this in your call because using it directly in an event handler means that this will be set to the object that invoked the handler. With this kind of code, this will just end up being window.

    Typically, best practice avoids assigning event handlers directly in markup. Instead, use addEventListener in your JS, at which point you can also assign the this pointer using .bind(this):

    //Assume code is in some object class, so "this" is that object
    
    init: function () {
        var elem = document.getElementById("shipper_shop_name");
    
        //This is how you use an event handler off the "this" object
        elem.addEventListener("blur", this.blurHandler.bind(this));
    },
    
    blurHandler: function (e) {
        this._saveSettingsForm();
    }
    
    
    

    To summarize, whatever code you put inside an onblur="" attributegets executed immediately, so whatever you put there has to resolve to a function or else you'll crash. Typically we avoid putting such code directly in markup, because it's hard to debug, so placing it outside in JS and assigning a handler explicitly is generally the better way to do it.

    Kraig

    Author, Programming Windows Store Apps with HTML, CSS, and JavaScript, Second Edition, a free ebook from Microsoft Press. First edition (for Windows 8) also available.


    Wednesday, December 04, 2013 5:51 PM
  • Hello Kraig,

    Thank you for your reply. However it did not work for me...

    That can be a "stupid" question, but I am not really familiar with those methods, so I tried to use the "addEventListener" as it is mentioned in the documentation, however I don't know how to assign it after it loads the form. Full itemDetail.js content:

    (function () { "use strict"; WinJS.UI.Pages.define("/pages/itemDetail/itemDetail.html", { // This function is called whenever a user navigates to this page. It // populates the page elements with the app's data. ready: function (element, options) { /** GET FILE CONTENTS AND RETURN INTO OUTPUT (SELECTOR) HTML */ function _file_get_contents(url, output, carrier) { var xhr = new XMLHttpRequest(); xhr.open("GET", url, true); xhr.responseType = "text"; xhr.send(); // Asynchronously wait for the data to return xhr.onreadystatechange = function () { if (xhr.readyState == xhr.DONE) { /** ENABLE UNSAFE FUNCTION */ MSApp.execUnsafeLocalFunction(function () { /** RETURN DYNAMIC OUTPUT */ element.querySelector(output).innerHTML = xhr.response.replace("{$carrier}", carrier); }); } } // Report errors if they happen xhr.addEventListener("error", function (e) { element.querySelector(output).textContent = "Error: " + e + " Could not load url."; }, false); } function _request(url, oFormElement) { var xhr = new XMLHttpRequest(); xhr.open("GET", url, true); xhr.send(new FormData(oFormElement)); // Asynchronously wait for the data to return xhr.onreadystatechange = function () { if (xhr.readyState == xhr.DONE) { /** ENABLE UNSAFE FUNCTION */ MSApp.execUnsafeLocalFunction(function () { /** RETURN DYNAMIC OUTPUT */ element.querySelector(output).innerHTML = xhr.response; }); } } // Report errors if they happen xhr.addEventListener("error", function (e) { element.querySelector(output).textContent = "Error: " + e + " Could not load url."; }, false); } function _saveSettingsForm(eventInfo) { var nameInput = eventInfo.srcElement; console.log(nameInput); // Store the user's name for multiple sessions. var appData = Windows.Storage.ApplicationData.current; var roamingSettings = appData.roamingSettings; roamingSettings.values["userName"] = nameInput.value; } /** LOAD ITEM PARAMS */ var item = Data.resolveItemReference(options.item); /** INSERT TITLE IN PAGE */ element.querySelector(".titlearea .pagetitle").textContent = item.title; /** LOAD DYNAMIC CONTENT */ _file_get_contents("/models/" + item.carrier + "/form.html", "." + item.carrier, item.carrier); element.querySelector("." + item.carrier).style.display = "block"; /**/

    } }); })();

    Is there any way to make it loads the form.html and then assign the event in the elements of the form?

    Best Regards,

    Vitor de Souza

    Wednesday, December 04, 2013 6:27 PM
  • Once you have form.html loaded in the DOM, e.g. through setting an innerHTML property, you can use document.getElementById or document.querySelector to access any of those loaded elements. Once you have the element you want, you can call its addEventListener.
    Friday, December 06, 2013 5:59 PM