Access input value with jquery

So far, the only way we’ve found to create an input field in Hype is to add <input> to the innerHTML button thing (no idea what this is called) on a rectangle. Please let me know if there’s a better way of doing this because, if so, it may provide an easy solution to the issue we’re running into below.

Creating an input this way means that the auto-generated ID Hype creates applies not to the input field, but the rectangle <div> that houses it. This also seems to apply to events such as entering text. For example, if we write <input oninput="saveText()"> and then throw the following in the scene load function:

window.saveText = function() {
    localStorage.setItem(element.id, $(element).val());
}

we end up with a blank value because it returns not the value of the input, but the rectangle element the event fired on.

Of course, we could hard code the ID for each input in the innerHTML but that is cumbersome. Being able to use the auto-generated ID as our key would be much more efficient as we’ll have many inputs over many iBook pages, but how can we access the value of the child of the element this function is fired on?

TIA

Using the innerHTML is how we normally do it.

We then give the forms an id or name

 <form>
     Email: <input type="text" id="targetEmail" >
     
    </form>

and query for that in the other code.

var mailto = document.querySelector('#targetEmail').value;

Thanks Mark. I don’t think I made clear that we are trying to avoid hardcoding the IDs because, in any one iBook, we may have hundreds of places students could enter text.

Anyway, we figured it out. It was to do with where we had the code in Hype. When we put this in Head HTML, we got it working exactly as we wanted:

window.saveText = function(){
localStorage.setItem(document.title + event.target.parentElement.id, event.target.value);
}

The beauty of this code is that no matter how many text inputs you have in your iBook, this will store unique keys for them in localStorage using the auto-generated IDs Hype produces. No more hardcoding element IDs and looping through them to get and set values. Fantastic.

We added the document.title string to the key because we have a lot of iBooks potentially all on the same device and didn’t want to risk any auto-generated IDs being identical and causing issues.

well, it would be fantastic if Hype didn't auto-generate IDs every single time I preview the widget! :flushed:

I'm attempting to use call the function getLocalStorage() in the load function with

window.getLocalStorage = function() {
    var elements = document.getElementsByClassName("text-area");		
    for (var i = 1; i < elements.length; i++) {
        elements[i].value = localStorage.getItem(document.title + elements[i].parentElement.id);
    }
}

If I preview this in a browser, every time I refresh the page to check if my values remain, the IDs change and they return null.

just to mention -> the attribute 'contenteditable'

2 Likes

If hype did not auto ID what would you use?.

What I am saying is if it did not you would have to hard code an id anyway.

The Auto ID is a hype internal thing afaik. The id name Hype uses for it’s internal functions is overriden when you enter an ID.

Without a full understanding of your doc it would be hit and miss to give a full answer.

But in this case I think you would need to manually add your own IDs which would work with your getter setter for storage

1 Like

I always forget about that, and yes this cuts down on drilling down into an element for value and id.
Good call.

yes, we were hardcoding IDs and all works fine if we do that. But it’s labour-intensive and prone to error because every time we need a new input we have to add that ID. And if someone adds an ID that’s already been assigned to another input in the widget or misses a number in the sequence, we run into problems. Although Hype checks for duplicate IDs, it only does so if you enter them in the Inspector.

If we could rely on the auto-generated IDs it becomes a no-brainer. But now that I know they change every time and I’ve tested this out in iBooks and it doesn’t save text (although there could be another issue in the code), I’m not sure that this is a solution which is a shame.

not sure how this is a good call. We still have to add something to innerHTML of the text element and also add an id there if we want to access localStorage, no?

Maybe I've misunderstood the application of Hans-Gerd's very brief message.

You could probably give each element the same class name and run you own auto id naming code.
You would just need to test fully to make sure that ids always match up when given.

yep that’s something we can do and we’ve talked about that since discovering we can’t rely on Hype’s auto-generated IDs.

Very basic

    var theInputs = document.querySelectorAll('.textInput')
	var idCounter = 1
	for (i = 0; i < theInputs.length; i++) {
    theInputs[i].id = 'textInput' + idCounter;
    idCounter++
    theInputs[i].contentEditable = true
 
}

Be aware once you code an id like this Hype will have problems finding it and things like animations will break.

So further thinking is instead of adding an ID you add new indiviual class names the same way.
This leave the ids alone for Hype and gives you something to query for.

	var theInputs = document.querySelectorAll('.textInput')
	var idCounter = 1
	for (i = 0; i < theInputs.length; i++) {
    theInputs[i].classList.add('textInput_' + idCounter)  ;
    idCounter++
    theInputs[i].contentEditable = true
 
 console.log(theInputs[i])
}

yep… we were thinking along the same lines. I’ll have a mess with the contentEditable attribute once we’ve got some downtime to see if it speeds up our workflow at all. For now, going with hardcoding and will apply this all later. thanks for now

1 Like

To note.

This means you can add a rectangle element and set this attribute in code. You do not need to add any innerHTML like you do for a form.


For instance
A rectangle with a class name 'textInput' is found and the code then adds a unique class name and sets the contentEditable like suggested above.

We then use the getter for your storage item and get the result back for class item textInput_1

var storageResult = {"Input" :'textInput_1', "value": 'some text'} // in place of your storage getter
 
var textInput_item = document.querySelector('.' + storageResult.Input).innerHTML   = storageResult.value

or

    var storageResult = {'textInput_1':'some text'} // in place of your storage getter
	var textInput_item = document.querySelector('.textInput_1').innerHTML   = storageResult.textInput_1

--

cedits_idAuto copy.hype.zip (15.9 KB)


Also note I notice an odd result when using preview if I had the animation play head anywhere beyond 0.
Seems preview changes the order taking into account of the elements current position at preview time.
This may not be an issue when testing since you normally don't move inputs like I do in this example.

-- Update

This does seem to also do this in an export if the animated elememt is in a different position at the play head and you are viewing the animated timeline at the time of Export

(@jonathan, @Daniel ) I feel this is a bug , I would not expect this to occure on the export

To reproduce just move the play head away from the 0s position in the 'Untitled Timeline' in the example above. And then with the 'Untitled Timeline' still in view do your export to folder.

The DOM order changes from what it should be and therefore what should be element textInput_1 will be wrong..

In the example it should always be the animated element. ( hard coded)

2 Likes

Long ago, Hype generated IDs when the element was created. This lead to all kinds of problems of collisions and file-size bloating. Hype will continue to auto-generate at runtime.

But to help account for this, did you know that Hype can assign unique IDs to multiple selection? If you type an ID when you have 2+ selected elements, you'll get this dialog:

It sounds like this will probably help?


I do not recommend on relying on the DOM ordering, as this is an internal implementation detail and subject to change with future versions of Hype. For example, we changed the ordering in v3.5 from being element list based to using position coordinates to help with accessibility.

And...

... this appears to have been one bug from that change we will fix, and this will change the ordering again for documents. (good find!)

1 Like

yes, we're aware of that. Is it by design that z-index coincides with the IDs being added? In other words, higher ID numbers are placed on elements nearer the top of the stack. Duplicating an element, for example, always places it above the original.

Multi-select won't work with inputs on rectangles though, will it? I can only multi-select the rectangles and not the inputs within them. The rectangles get lovely IDs but my inputs are left blank.

A solution seems to be what Mark and Hans-Gerd are suggesting, but I'm wondering how we combine it with running functions on the inputs on each key press. We use these to do things like place text into localStorage or run some regex to allow live checking. As far as I can tell, this has to be on the innerHTML to work in Hype. Can't think of an alternative at the mo.

Very much appreciate the discussion though.

If you're referring to the using the multiple ID assignment, I don't think this is specifically by design glancing at the code; there's probably a sort that snuck its way in above where the assignments are made. However it is probably good behavior that it is consistent.

For duplication, this is by design; typically you'd want the duplicate to be above the element you've made, otherwise you won't be able to see it! (This is more clear with copy/paste where there may be some differences and the goal is that they are similar).

If you're referring to elements within innerHTML, this is correct -- Hype's inspector only works on Hype elements and not what is defined inside.

You could do DOM parent/child traversal. For example, if you have an event on an <input> in Inner HTML, this event could take that element and look up through parentNode objects until it finds one with an expected class/ID, and then use that ID for saving.

hm ... i'd say the events work almost the same ... though tests within iBooks-environment should be made ...

var allInputElementsWithinDocument = document.querySelectorAll('.editable');

allInputElementsWithinDocument.forEach(

function(inputElement){
inputElement.setAttribute('contenteditable', 'true');

inputElement.oninput = function(e){console.log(e)}

}



)