Undefined - Trying to pass a value from a form to a JS function using jQuery and getting it very wrong - javascript

I'm trying to learn how to use JS in order to create a unit converter for a site I'm working on.
I did have intentions of trying to accomplish it using PHP but someone pointed out how inefficient it would be and so I'm now trying to learn JS to carry out the same tasks.
I've written a very small test function to add two numbers, it worked fine. I then adjusted it slightly to take in a few more params and to check a couple of conditions, again that worked fine - I created a new object and passed the variables in directly.
I now need to pass the values from the form that I have into this function in order to compute the sum and output the result. I keep getting an error of 'undefined'. I've googled and read but can't seem to find a solution.
so far I have:
<script type="text/javascript">
function Convert(from, to, units){
this.from = $("#from").val();
this.to = $("#to").val();
this.units = $("#units").val();
}
Convert.prototype.convertThem = function(){
if(this.from == "degC"){
if(this.to == "degF"){
return this.units * 347956757524;
}
}
}
calcTempTest = new Convert(this.from, this.to, this.units);
alert(calcTempTest.convertThem());
console.log(calcTempTest);
</script>
Could anyone tell me what I'm doing wrong please? The 'to','from' and 'units' are the id's from the form.
The Form:
<div class="form">
<label for="units">Units:</label>
<input type="text" name="units" id="units" class="required digits" />
</div>
<div class="form">
<label for="from">Convert From:</label>
<select name="from" id="from">
<option value="from">-Select an Option-</option>
</select>
</div>
<div class="form">
<label for="to">Convert Into:</label>
<select name="to" id="to">
<option value="to">-Select an Option-</option>
</select>
</div>
<div class="form">
<label> </label>
<input type="submit" name="submit" value="Convert!" />
</div>
many thanks.

Explanation
Your select selected option value onLoad both are "from" and "to". Since these are not equal to "degF" and "degC", your assignments won't go on, the resulting variable will be undefined since no value will be asssigned to it.
Solution
Add several option to your select or change their default value. I also added a default value to the input.
HTML
<input type="text" name="units" id="units" value="12" class="required digits" />
<option value="degC">-Select an Option-</option>
<option value="degF">-Select an Option-</option>
EDIT
I have added a JSFiddle here which executes the script on the button click with the following modifications to JavaScript:
NOTE: I also added the real formula.
JavaScript/jQuery
$('input[name="submit"]').click(function () {
var c = new Convert();
alert(c.convertThem());
});
function Convert() {
this.from = $("#from").val();
this.to = $("#to").val();
this.units = $("#units").val();
}
Convert.prototype.convertThem = function () {
if (this.from == "degC") {
if (this.to == "degF") {
return this.units * 1.8 + 32;
}
}
}

I think when you create the convert object you're trying to pass variables that don't exist:
calcTempTest = new Convert(this.from, this.to, this.units);
I'm pretty sure this stands for window at that point and windw.from is undefined. You don't seem to be doing anything with these values anyway so you could change it to:
calcTempTest = new Convert();
Maybe the following answer could help you out with what this stands for in JS: Prototypical inheritance - writing up
Here is some minimally working code:
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<script type="text/javascript" src="jquery-1.10.1.js"></script>
</head>
<body>
<div class="form">
<label for="units">Units:</label>
<input type="text" name="units" id="units" class="required digits" />
</div>
<div class="form">
<label for="from">Convert From:</label>
<select name="from" id="from">
<option value="degC">degC</option>
</select>
</div>
<div class="form">
<label for="to">Convert Into:</label>
<select name="to" id="to">
<option value="degF">degG</option>
</select>
</div>
<div class="form">
<label for="output">Output:</label>
<input type="text" id="output" />
</div>
<div class="form">
<label> </label>
<input type="submit" id="subm" name="submit" value="Convert!" />
</div>
<script type="text/javascript">
(function () {
function Convert(from, to, units) {
// when convert is created set a reference to the input elements
this.$from = $("#from");
this.$to = $("#to");
this.$units = $("#units");
this.$output = $("#output");
}
Convert.prototype.convertThem = function () {
// this.$... is a jQuery object containing the input elements
if (this.$from.val() == "degC") {
if (this.$to.val() == "degF") {
this.$output.val( this.$units.val() * 347956757524);
}
}
}
calcTempTest = new Convert();
$("#subm").on("click", null, null, function () {
calcTempTest.convertThem();
});
})();//anonymous funciton, no variables in global scope
</script>
</body>
</html>

There are several issues with your code. Most of them have been resolved in the accepted answer, but I wanted to provide some more insights that would help you create more reusable code in the future.
Since I have already created a jsfiddle with my own example, it will be a shame to let it go to waste so I will post it anyway with some comments.
Using constructor parameters
function Convert(from, to, units, res){
this.from = from;
//etc...
}
Passing parameters to an object's constructor (and using them) makes it more reusable. You did not use the passed parameters and the selected answer used what I assume was your original solution (hard-coding the element values into the object upon construction).
This way you can have multiple instances of the converter on the same page, you can put its code in an external file as it gets more complex and only put the instantiation logic in the page itself (if your page structure changes, there is no need to change the external file, just update the provided constructor parameters).
Storing node references instead of values
The other thing I wanted to point out is the way the calculation is done.
Your implementation requires a new object to be created for each calculation. I find it much better to create a single Converter and obtain the values only when required. That it the reason I stored a reference to the form field DOM nodes and did not store their values.
$("#btnConvert").click(calcTempTest.convertThem.bind(calcTempTest));
I used bind(...) in the click attachment to preserve the object's scope.
Good luck!

Related

Cant Get Answer Back In answer Box NAN is being shown

it does not returns prpoer answer it returnes NAN in Answer
<html>
<head>
<script type="text/javascript">
function pro(n,p)
{
var number=parseInt(n);
var powe=parseInt(p);
for(var i=1;i<powe;i++)
{
number*=number;
}
document.getElementById("answer").value=number;
}
</script>
</head>
<body>
<form name="F" >
Enter Number <input type="text" name="num" id="num"/>
Enter Power <select name="powe" id="powe">
<option value="2" >square</option>
<option value="3" >cube</option>
</select>
Answer<input type="text" name="Answer" id="answer" />
<input type="button" onClick="pro(num,powe)" value="Calculate" />
</form>
</body>
</html>
The issue is this: onClick="pro(num,powe)". Instead of the values for num and powe being gotten from the input elements and passed into the pro function, the actual element references (which are not numbers) are being passed.
To solve this problem, you'll need to get the values of the elements. But, before you just make a quick edit to your code, don't use inline HTML event attributes (onclick) in the first place. Instead, separate your JavaScript from your HTML and set up event handlers using modern standards with .addEventListener() as shown below.
Also (FYI):
Since you aren't actually submitting form data anywhere, you don't
need a <form> element.
It's not necessary to use parseInt with p.value because that
value is coming from your select and you've already set those at
whole numbers.
Don't bother with self-terminating tags (<input />) as you
gain nothing from using them.
If you are expecting only numeric input, it's better to use input
type=number which restricts the user input to numbers. Making this change also saves you from worrying about parseInt on the input number being misinterpreted as other bases than 10.
Since you don't want the user to be able to change the result of the
operation, it's better to display it in a non-editable element, like
a span.
It's a good idea to move your <script> element to just before the
closing body tag because, by the time the parser reaches that
point, all your HTML elements will have been parsed into memory.
<html>
<head>
</head>
<body>
<div>
Enter Number <input type="number" name="num" id="num">
</div>
<div>
Enter Power
<select name="powe" id="powe">
<option value="2">square</option>
<option value="3">cube</option>
</select>
</div>
<div>
Answer <span id="answer"></span>
</div>
<div>
<input type="button" value="Calculate">
</div>
<script>
// Get references to the inputs, the answer container and the button
let inputNum = document.getElementById("num");
let power = document.getElementById("powe");
let answer = document.getElementById("answer");
let btn = document.querySelector("input[type='button']");
// Set up the click event handler for the button
btn.addEventListener("click", function(){
// Now you need to get the input values and pass them
// to the function that will act with them
pro(inputNum.value, power.value);
});
function pro(n,p) {
var number = parseInt(n);
for(var i = 1; i < p; i++) {
number *= number;
}
answer.textContent = number;
}
</script>
</body>
</html>
Try
document.getElementById("answer").innerHTML = number

Getting another element through a method thats related to the current operation

Sorry for the bad title, simple couldn't figure out how to explain my problem.
Let's say i have 4 of these fields, and not just one. I want to increment or decrement each input field. Each input field has a "+" and "-" that does incremental and decremental tasks.
I have setup a method that register the v-on click even to a method. But how do i get what input field it was incremented on, cause 'this' would return the buttons of +/-
normally i would just use jquery with .parent().find('.input-number'); but i feel like this is dirty, and excessive for such a small thing. most be a better approach?
This is my markup
<div class="form-group">
<span class="input-number-decrement" v-on:click="decrement()">–</span>
<input class="input-number form-control" name="pack1" id="pack1" type="text" value="0" min="0">
<span class="input-number-increment" v-on:click="increment()">+</span>
</div>
and looks like this
example of the field
any help would great, since i'm stuck at this part :)
I have created one javascript function for increment and decrement value by 1.
HTML
<div class="form-group">
<span class="input-number-decrement" v-on:click="inc_dec('dec')">-</span>
<input class="input-number form-control" name="pack1" id="pack1" type="text" value="0" min="0">
<span class="input-number-increment" v-on:click="inc_dec('inc')">+</span>
</div>
Javascript
<script type="text/javascript">
function inc_dec(flag){
var pack1 = document.getElementById('pack1');
var inc_dec_by = 1;
if(flag=='inc'){
pack1.value = parseInt(pack1.value)+inc_dec_by;
}
if(flag=='dec'){
pack1.value = parseInt(pack1.value)-inc_dec_by;
}
}
</script>
I am assuming above code is a vue component.
<div class="form-group">
<span class="input-number-decrement" v-on:click="decrement()">–</span>
<inputn v-model="value" class="input-number form-control" name="pack1" id="pack1" type="text" value="0" min="0">
<span class="input-number-increment" v-on:click="increment()">+</span>
</div>
In the script define a variable to hold the value.Then manipulate values using defined methods
<script>
export default{
data: {
value
},
methods: {
decrement: function (event) {
},
increment: function (event) {
}
}
}
</script>

AngularJS: Target a form with Controller As syntax in an object

Note: I did look around here on SO for solutions, yet no one had the additional issue of the function being in an object.
I have a form in my Angular JS app:
<div ng-app="plunker">
<div ng-controller="PMTController as pmt">
<form name="myForm">
<div class="form-group">
<input type="text" class="form-control" />
</div>
<button class="btn btn-primary" ng-click="pmt.search.resetSearchForm()">Reset</button>
</form>
</div>
</div>
Further, I have a controller with an object:
app.controller('PMTController', function($log) {
var _this = this;
_this.search = {
resetSearchForm: function () {
$log.debug('test');
// how to target the form?
}
};
})
My ng-click works, as the log.debug works. But no amount of tweaking to target the form so that I can reset the entire thing (empty all the fields) works.
I can do $window.myForm.reset(); but how could I do this from angular?
Note please my main issue/question is how to correctly target the form from inside that resetSearchForm function in the search object.
Note I tried changing the form name to pmt.myForm or pmt.search.myForm to no avail.
I tried $setPristine and $setUntouched() but they don't seem to clear the fields.
I know I can assign a model and assign it to all the form controls, but this is for a prototype so I'd rather do a simple reset.
I made a pen: https://codepen.io/smlombardi/pen/YWOPPq?editors=1011#0
Here is my take on your codepen that will hopefully resolve the issue:
https://codepen.io/watsoncn/pen/YWOXqZ?editors=1011
Explanation:
Angular's documentation provides an example of a "Form Reset" button, but you can apply the same logic towards resetting after submission:
Documentation:https://docs.angularjs.org/guide/forms
with a plunker:
Live Example:https://plnkr.co/edit/?p=preview
The example shows the use of Angular's copy method that creates a deep copy of whatever you pass it as a parameter and assigns it to the ng-model that is put on a particular input field. In this case they simply pass it an empty master object.
You need to make sure to add an ng-model attribute to your inputs, then create a reset function that can run after submission. Another common option would be to simply set each input's ng-model to empty strings in the submission function, such as $scope.inputModel = ""
Is this what you were hoping for? I might have misunderstood the question. I will happily take another crack at it if there is still confusion.
To get the form in your controller you just need to name your form this way:
<form name="pmt.myForm">
Here's a complete demo:
(function() {
"use strict";
angular
.module('plunker', [])
.controller('PMTController', PMTController);
PMTController.$inject = ['$log'];
function PMTController($log) {
var _this = this;
_this.model = {};
_this.search = {
resetSearchForm: function() {
console.log(_this.myForm); // -> Form reference
_this.model = {};
}
};
}
})();
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body ng-controller="PMTController as pmt">
<div class="col-md-12">
<form name="pmt.myForm">
<div class="form-group">
<input type="text" ng-model="pmt.model.example" class="form-control" />
<input type="text" ng-model="pmt.model.example2" class="form-control" />
<input type="text" ng-model="pmt.model.example3" class="form-control" />
</div>
<button class="btn btn-primary" ng-click="pmt.search.resetSearchForm()">Reset</button>
</form>
<hr> All fields:
<pre ng-bind="pmt.model | json"></pre>
</div>
</body>
</html>

jQuery autocomplete for innerHTML generated textbox

I realize similar questions have been asked thousands times and yet it doesn't seem to work for me. I have a textbox called "movieTitle", it is generated via Javascript by clicking a button. And I'm calling jQueryUI autocomplete on that textbox just like in the official example http://jqueryui.com/autocomplete/#remote.
It works well if I hardcode "movieTitle" in the original page; however it just fails when I create "movieTitle" by changing the innerHTML of the div "formsArea". searchMovies.php is the same with search.php from the example. I had tried many answers from internet and from here. I learned that I would have to use .on() to bind the dynamic element "movieTitle". Still it doesn't seem to work. Even the alert("hahaha") works. Thanks for your time. :) Here's my script:
$(function()
{
$(document).on('focus', '#movieTitle', function(){
//alert("hahaha");
$("#movieTitle").autocomplete({
source: "../searchMovies.php",
minLength: 2
});
}
);
window.onload = main;
function main()
{
document.getElementById("movieQuery").onclick = function(){showForms(this.value);};
document.getElementById("oscarQuery").onclick = function(){showForms(this.value);};
// displays query forms based on user choice of radio buttons
function showForms(str)
{
var heredoc = "";
if (str === "movie")
{
heredoc = '\
<h1>Movie Query</h1>\
<form action="processQuery.php" method="get">\
<div class="ui-widget">\
<label for="movieTitle"><strong>Name: </strong></label>\
<input type="text" id="movieTitle" name="movieTitle" />\
<input type="submit" name="submitMovie" value="Submit" />\
</div>\
</form>';
//document.getElementById("formsArea").innerHTML = heredoc;
//$("#formsArea").append(heredoc);
$("#formsArea").html(heredoc);
}
else if (str === "oscar")
{
heredoc = '\
<h1>Oscar Query</h1>\
<form action="processQuery.php" method="get">\
<strong>Name: </strong>\
<input type="text" name="oscarTitle" />\
<input type="submit" name="submitOscar" value="Submit"/>\
</form>';
document.getElementById("formsArea").innerHTML = heredoc;
}
}
}
});
The HTML is:
<form action=$scriptName method="get">
<label for="movieQuery"><input type="radio" name="query" id="movieQuery" value="movie" />Movie Query</label>
<label for="oscarQuery"><input type="radio" name="query" id="oscarQuery" value="oscar" />Oscar Query</label>
</form>
<div id="formsArea">
<b>Please choose a query.</b>
</div>
You should check for the URL you're sending an AJAX request to. The paths in script files are relative to the page they're being displayed in. So albeit your script is in /web/scripts/javascripts/js.js, when this file is included in /web/scripts/page.php, the path to /web/scripts/searchMovies.php should be searchMovies.php instead of ../searchMovies.php because your script is being used in /web/scripts/.
Good ways to avoid such confusion is to
a. use absolute URL
b. the URL that're relative to root of your domain (that start with a /),
c. or define your domain's path in a variable, var domain_path = 'http://www.mysite.com/' and use it in your scripts.
I hope it clarifies things :)
Relative Paths in Javascript in an external file

Error when trying to refer to a field by name

I am getting an error (document.my_formm.fieldName.value is null or not an object) from the below code:
<html>
<head>
<title>(Type a title for your page here)</title>
<script language=JavaScript>
function check_length(my_formm,fieldName)
{
alert(fieldName);
alert(document.my_formm.fieldName.value);
}
</script>
</head>
<body>
<form name=my_form method=post>
<input type="text" onChange=check_length("my_form","my_text"); name=my_text rows=4 cols=30 value="">
<br>
<input size=1 value=50 name=text_num> Characters Left
</form>
</body>
</html>
Your check_length function is using variables to identify the form and field names, however, by using dot notation, you are referring to a element of document named my_formm. When you are are using variable names, you should use the bracket notation instead:
function check_length(my_formm,fieldName)
{
alert(fieldName);
alert(document[my_formm][fieldName].value);
}
Also, you should really quote attributes in your input:
<input type="text" onKeyPress="checkCompanyName();" onChange="check_length('my_form', 'my_text');" name="my_text" rows="4" cols="30" value="">
In your javascript you have referred to the form as 'my_formm' i.e. you have an extra 'm' at the end which is not present in the HTML, this could be your problem.
Why does your JavaScript method take in that first parameter if it never uses it?
Just do onChange=check_length(this)
and in your function
function check_length(element)
{
// element points to the element in question
// element.form points to the form if you need it
alert(element.value);
}
In general it would be nice to write WHAT error are you getting...
anyhow checkCompanyName is not defined in the code you wrote.
Also you're passing two strings as variable, they do not have properties...
A better way to do this:
<script type="text/javascript">
function checkLength()
{
inp = document.getElementById("myInput");
len = document.getElementById("len");
len.value = inp.value.length;
}
</script>
<input id="myInput" onkeyup="checkLength()" />
<input id="len" />
EDIT AFTER COMMENT:
<script type="text/javascript">
function checkLength(inputname, lenname)
{
inp = document.getElementById(inputname);
len = document.getElementById(lenname);
len.value = inp.value.length;
}
</script>
<input id="myInput" onkeyup="checkLength('myInput', 'len')" />
<input id="len" />
document.my_formm looks for a form named my_formm. You need to use the associative array sintax instead, like document[my_formm], which will pass the value in my_formm at runtime, rather than looking for a property in the document object called my_formm (which doesn't exist).

Categories