Am trying to chache DOM using namespace but when I call I get "undefined" instead of jQuery object
<form id="create_profile">
<input type="text" name="name"/>
<input type="text" name="email" />
<input type="text" name="password" />
<input type="text" name="passwordconfirm" />
<span onclick="profile.create()">valider</span>
</form>
Js:
var profile = {
create: function(){
alert(profileFields.test); // show done!
alert(profileFields.create_form.attr('id')); // show undefined instead of create_profil
}
}
var profileFields = {
test: "done!",
create_form: $("#create_profile"),
$email: $("input[name='name']", this.create_form),
$password: $("input[name='pass']", this.create_form),
$passwordconfirm: $("input[name='passconfirm']", this.create_form),
$name: $("input[name='email']", this.create_form),
$tel: $("input[name='tel']",this.create_form)
}
This tells us that your JavaScript code is running before that element exists, so $("#create_profile") returns an empty jQuery object. Calling attr on an empty jQuery object returns undefined. If your script tag is higher up in the HTML than the elements it refers to, the elements won't exist as of when the script runs.
Either
Put the script tag at the very end of the HTML, just before the closing </body> tag, or
Use jQuery's ready to hold up execution of your code until "DOM ready."
#1 is preferred unless you don't control where the script tag goes. More:
Best Practices for Speeding Up Your Web Site
Google Closure engineers on when DOM elements are ready for scripting
You probably simply did not wait until the DOM was ready.
Wrap your code in:
$(function () {
//your code
});
Related
I am trying to verify if my checkbox is checked. I have looked up many solutions, and they all point to this :
html :
<body>
<input type="checkbox" id="terms" name="terms" />
<label for="terms">Agree with terms</label>
javascript :
let checkbox = document.querySelector("#terms");
console.log(checkbox.checked);
But the console is returning :
"Uncaught TypeError: Cannot read properties of null (reading 'checked')"
There is no other code interfering with this as I stripped it down to this small example to see if my project was interfering with the functionality, but even with the most basic code '.checked' is returning an error. Has there been an update to this feature?
<input type="checkbox" id="terms" name="terms" />
<label for="terms">Agree with terms</label>
<script>
let checkbox = document.querySelector("#terms");
checkbox.addEventListener('change', () => {
console.log(checkbox.checked);
})
</script>
or
let checkbox = document.querySelector("#terms");
console.log(checkbox.checked);
I figured out the issue, I was not including 'defer' in my script.js link. Its all fixed thank you!
You will run into unexpected issues if you use defer.
Instead, use the DOMContentLoaded event to trigger your script.
Using defer allows that script to be executed after the DOM is done being parsed, but before the DOM content is loaded.
It’s likely that you’re deferred script will run too soon and crash when you try to access an element that doesn’t exist yet.
You can link your script in the <head> as long as you have it run when that event fires off.
document.addEventListener('DOMContentLoaded', function () {
let checkbox = document.querySelector("#terms");
checkbox.addEventListener('change', () => {
console.log(checkbox.checked);
})
})
EDIT: To answer the question from your comment above, linking to the JavaScript file in the head means that it will run before the html is built.
Putting the code in a script tag in the html means that it won’t be executed until DOMContentLoaded has triggered.
That happens after the link using defer and after the script is executed from the head.
Wrap your code up to only execute on DOMContentLoaded and you’ll avoid a lot of headaches in the future 😎
Using Polymer, I learned to understand well the difference between light DOM (whatever is in the element) and local DOM (the "hidden" side of the story).
<iron-form> (which is used like <form is="iron-form"></form>) is a little different as it doesn't have local DOM.
Now I have a custom-made widget (which is actually available in GitHub) where you go:
<hot-form-validator success-message="Record saved!">
<form is="iron-form" id="form" method="post" action="/stores/polymer">
<paper-input required id="name" name="name" label="Your name"></paper-input>
<paper-input required id="surname" name="surname" label="Your surname"></paper-input>
<paper-button type="submit" raised on-click="_submit">Click!</paper-button>
</form>
</hot-form-validator>
Now, hot-form-validator needs to get the form, and then look -- within the form -- for a specific button (with type=submit). So, I have:
(remember that this.form is the form):
attached: function(){
var paperButton = this.form.$$('paper-button[type=submit]');
...
}
It works, but it doesn't make sense that it does since $$ should be only for local DOM, whereas paper-button is actually in the form's light DOM.
attached: function(){
var paperButton = this.form.queryEffectiveChildren('paper-button[type=submit]');
This works, but I wonder if it's the best way to go.
Or... since there is no shadow DOM, should I simply no bother worrying about all this, and simply use DOM as always since there is no light/local DOM to deal with?
See https://www.polymer-project.org/1.0/docs/devguide/local-dom#light-dom-children
If you add an id to the <content id="someId"></content> then you can use
var result = this.getContentChildren('#someId');
and then look up the desired element in the result.
You could for example create a specific <content> tag for the submit button like
<dom-module ...>
<template>
...
<content></content>
<content id="submitButton" select="paper-button[type=submit]"></content>
...
</template>
</dom-module>
and then get the element using
var submitButton = this.getContentChildren('#submitButton')[0];
This code is working
this.form.$$('paper-button[type=submit]');
because this.$$ forwards to querySelectorAll(...) and in shady DOM encapsulation is just emulated and doesn't prevent querySelectorAll(...) to find other children than local DOM children.
You can also use
var submitButton = Polymer.dom(this).querySelector('paper-button[type=submit]');
My script looks like this:
<script>
var queryString = window.location.search;
var pos = queryString.indexOf("?refer=");
var referEmail = queryString.substring(pos+7);
document.getElementById("referral-code").value = referEmail;
</script>
And the HTML codes look like this:
<form action="/" method="POST">
<label for="referral-code">Referrer's code (hidden): </label>
<input type="text" name="referral_code" id="referral-code"/>
<br/>
<label for="me-email">My Email: </label>
<input type="text" name="self_email" id="me-email"/>
<br/>
<input type="submit" value="Step Inside" />
</form>
I think it may be cleaner to put the <script> tag in <head>. However, I am not sure whether the script will wait to be executed until the DOM in <body> is processed. If not, will document.getElementById("referral-code") returns undefined?
Does anyone have ideas about whether a script in <head> will wait to be executed until the whole HTML is loaded? And should I put the DOM manipulating script in <head> or before the closing </body>?
if you want to put in head then make sure you put it in
$(document).ready(function(){
});
otherwise you can put it after the DOM completion (just right before </body> )
If placed in the header the script will execute before DOM loads and won't add the referal code to the input (as it doesn't yet exist).
I'd suggest putting it before the tag.
$(document).ready(function(){}); vs script at the bottom of page has some more information on some of the pros/cons/differences of script tag/file location.
I have a pretty typical form with some inputs and a submit button, however when I try to use jQuery's find() method, I get some annyingly inconsistent results. The are as follows:
$("#frmContact").find(":submit") -> undefined is not a function
$("#frmContact").find(".btn") -> works
$("#frmContact").find(".btn.secondary") -> undefined is not a function
$("#frmContact").find("input[type=submit]") -> works
$("#frmContact input:submit") -> undefined is not a function
$("input[type=submit]", "#frmContact") -> undefined is not a function
$("form").find("input") -> works
$("form").find("input[type=submit]") -> undefined is not a function
What's going on here and how do I fix this?
I'm using jQuery 1.11 after upgrading from 1.9 hoping that it will fix the issue. There's also Angular on the page and I'm calling this code from the console after everything is loaded.
My form, just in case you need it is as follows [EDIT] updated to show actual HTML output with Angular classes and directives:
<form ng-submit="saveContact($event, '/applicants/update_contact?id=1593')" class="ng-pristine ng-valid" _lpchecked="1" id="frmContact">
<h4 class="section-header">Applicant Contact Information</h4>
<field id="email" type="text" model="applicant.email" label="Email address" class="ng-isolate-scope">
<div ng-class="['field', isRequired()]" class="field"> <!-- Text/File/Password Field -->
<label ng-bind="label" class="ng-binding">Email address</label>
<input type="text" ng-model="model" class="ng-pristine ng-valid">
</div>
</field>
<div class="field">
<input type="submit" value="Save" class="btn secondary">
</div>
</form>
My JavaScript libraries are loaded in this order:
jQuery 11
jQuery UI
Angular
My app.js
Scripts are loaded at the bottom of the page.
AngularJS comes with JQLite, a lightweight smaller verison of jQuery, which is the one you are using here and that gives you unexpected results.
In order for Angular to works with the full jQuery, you need to make sure that you load jQuery before Angular. So watch your <script> tags order.
So it turns out the hand that held the knife to my throat was my own.
Earlier in the application's development it was useful to add a couple helper methods on the Object prototype by doing Object.prototype.findId = function() { ... }. Turns out this raised all sorts of hell when trying to perform the find() method in jQuery.
I fixed it by turning this:
Object.prototype.myMethod = function() { ... }
into this
var specialObject = function(object) {
return {
myMethod: function() { ... }
}
}
I didn't realize that my earlier approach was such bad practice until I read this: Extending Object.prototype JavaScript
Thank you all for your help, guys.
I am using Chrome 30.0.1599.101 and have issue with name element: it has no properties.
<html>
<body>
<form>
<input name="name" id="name" type="text">*<br>
<input name="pass" id="pass" type="text">*<br>
</form>
<script>
var name = document.getElementById("name");
var pass = document.getElementById("pass");
console.log(name); // no properties
console.log(pass); // everything ok
</script>
</body>
</html>
Why has name element has no properties? It's not only the console issue - the properties are not accessible in the code. However, everything works fine in Firefox browser. Even in the fiddle (by Gurpreet Singh) with the very same code in the same browser everything works. I tried <!DOCTYPE html5> as Uooo suggests, tried to reset the browser, but still no luck on localhost.
Here is a screenshot:
If I change the name name to something else, the properties are visible.
name is already a global property (a property of window), and not only that, it is kinda typed (String).
var name = ... is essentially the same as as saying window.name = .... Use another variable name that is actually not taken yet and you should be fine.
Missing <head> and <title>, maybe that helps, it's invalid HTML without them.
jsfiddle does automatically insert those tags, which could explain why it works there but not locally.
Don't get confused by Green arrow answer,
you don't close an input tag, but not the br and vice versa. All single-tags in XHTML need to be closed to be valid, but in HTML4 and HTML5 you don't close any single-tag at all.
I would suggest following changed version which works as intended for me in
navigator.userAgent
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1678.0 Safari/537.36"
Code
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<script>
document.addEventListener('readystatechange', function(event) {
if (event.target.readyState !== "complete") {
return;
}
var name = document.getElementById("name");
var pass = document.getElementById("pass");
console.log(name);
console.log(pass);
}, false);
</script>
</head><body>
<form>
<input name="name" id="name" type="text">*<br>
<input name="pass" id="pass" type="text">*<br>
</form>
</body></html>
Explanation
script elements should be in the head element of a HTML document.
script code dealing with the DOM needs to run after the document is fully loaded.
Implicitly Fixed Issues
script code should not run in global scope where var name and pass may clash with existing variables. It now runs in the scope of the anonymous event listener function.
Remaining Problems
Use type="password" for password fields.
Use the value attribute to default input type values.
Better use div elements to layout input elements vertically instead of br elements.
I don't know if that cause the error but you should at least close your input
<html>
<body>
<form>
<input name="name" id="name" type="text"/>*<br>
<input name="pass" id="pass" type="text"/>*<br>
</form>
</body>
</html>
The fiddle works for me too...
Do you have any warnings &/or errors in your chrome console ?
You should also used your script in that function :
<script>
$(function() { //shortcut for document ready
//Get your elements here otherwise you can't be sure that dom is loaded.
});
</script>
if you don't use jquery then it's quite a mission to detect when dom is loaded if you want a Xbrowser solution, a lot of topic are talking about that.