So here is my JavaScript array:
var champions = {
"Aatrox":["Blood Well","Dark Flight", "No Q2", "Blood Thirst", "Blood Price", "Blades of Torment", "No E2", "Massacre"],
"Ahri":["Essence Theft","Orb of Deception", "Fox-Fire", "Charm", "Spirit Rush"],
"Akali":["Twin Disciplines", "Mark of the Assassin", "Twilight Shroud", "Crescent Slash", "Shadow Dance"],
"Alistar":["Trample","Pulverize","Headbutt","Triumphant Roar","Unbreakable Will"],
"Amumu":["Cursed Touch","Bandage Toss","Despair","Tantrum","Curse of the Sad Mummy"]
};
Now I get a variable from a PHP form with champion name so e.g. Akali and also with a spell name so e.g. Twin Disciplines now I want to check if that spell and champion exists in my array and if so on which position it is so:
var championName = echo $champion;
var Spell = echo $championSpells[1][$j];
if($.inArray(championName, champions)==-1){
var existsInArray = false;
} else{
var existsInArray = true;
}
And at this point im really confused Spell is = 'Twin Disciplnes' championName is = 'Akali' so with those examples I would want to retrive 1 if it was for example 'Mark of the Assassin' I would want to retrieve 2 because it is 2nd in order.
In Javascript you can use Array.prototype.indexOf() for the search of an item in an array. The result is the index starting with 0. If not found, the -1 is returned.
var champions = {
"Aatrox": ["Blood Well", "Dark Flight", "No Q2", "Blood Thirst", "Blood Price", "Blades of Torment", "No E2", "Massacre"],
"Ahri": ["Essence Theft", "Orb of Deception", "Fox-Fire", "Charm", "Spirit Rush"],
"Akali": ["Twin Disciplines", "Mark of the Assassin", "Twilight Shroud", "Crescent Slash", "Shadow Dance"],
"Alistar": ["Trample", "Pulverize", "Headbutt", "Triumphant Roar", "Unbreakable Will"],
"Amumu": ["Cursed Touch", "Bandage Toss", "Despair", "Tantrum", "Curse of the Sad Mummy"]
};
function getPos(o,n, s) {
return n in o && o[n].indexOf(s);
}
document.write(getPos(champions, 'Akali', 'Twin Disciplines') + '<br>');
document.write(getPos(champions, 'Akali', 'Mark of the Assassin') + '<br>');
Related
I am trying to parse certain span tags from Winmo profiles (e.g., like https://open.winmo.com/open/decision_makers/ca/pasadena/jorge/garcia/489325) which do not have id or class values, i.e.,
<span itemprop="email">j****#***********.com</span>
<div itemscope="" itemprop="address" itemtype="http://schema.org/PostalAddress">
<span itemprop="streetAddress">177 East West Colorado Boulevard</span>
<span itemprop="addressLocality">Pasadena</span>,
<span itemprop="addressRegion">CA</span>
<span itemprop="postalCode">91195</span>
<span itemprop="addressCountry">USA</span>
I found two old StackOverflow examples helpful (this and this), but I am still getting null values for each of the 9 span itemprop-matching lines on the webpage with the following code:
var nodes=[], values=[];
var els = document.getElementsByTagName('span'), i = 0, whatev;
for(i; i < els.length; i++) {
prop = els[i].getAttribute('itemprop');
if(prop) {
whatev = els[i];
nodes.push(whatev.nodeName); // provides attribute names, in all CAPS = "SPAN"
values.push(whatev.nodeValue); // for attribute values, why saying null if els[i] is fine?
console.log(values); // (whatev) outputs whole thing, but it seems values is what I need
// break; // need this? seems to prevent values after first span from generating
}
}
How do I return just the partly-hidden email value (j****#***********.com) and the postalCode (91195) from these kinds of pages? I need the solution in plain JS because I will be compressing it into a bookmarklet for others.
You can grab the assignments from the itemprop attribute.
something like this:
function getItemPropsAsJSON(){
var ob = {};
Array.from(document.getElementsByTagName('span')).forEach(el=> {
var key = el.getAttribute('itemprop');
var val = el.innerText;
if (key && val) ob[key] = val;
});
return ob;
}
/* expected output:
{
"name": "Jorge Garcia - Co-Founder & Chief Technology Officer, ICONIC | Contact Information, Email Address, Phone Number, Budgets and Responsibilities",
"email": "j****#***********.com",
"telephone": "(347) ***-****",
"streetAddress": "177 East West Colorado Boulevard",
"addressLocality": "Pasadena",
"addressRegion": "CA",
"postalCode": "91195",
"addressCountry": "USA"
}
*/
You may want to normalize the keys if you use this elsewhere, as the itemprop attributes may not always convert to the ideal object notation format. To do that, use the following:
function normalizeObjectNotation(key){
return key && typeof key == 'string' && /[A-Z]/.test(key) && /\W+/.test(key) == false
? key.trim().split(/(?=[A-Z])/).reduce((a,b)=> a+'_'+b).replace(/^\d+/, '').toLowerCase()
: key && typeof key == 'string' ? key.trim().replace(/\W+/g, '_').replace(/^\d+/, '').toLowerCase()
: 'failed_object';
}
function getItemPropsAsJSON(){
var ob = {};
Array.from(document.getElementsByTagName('span')).forEach(el=> {
var key = el.getAttribute('itemprop');
var val = el.innerText;
if (key && val) ob[normalizeObjectNotation(key)] = val;
});
return ob;
}
getItemPropsAsJSON()
/* Expected Output:
{
"name": "Jorge Garcia - Co-Founder & Chief Technology Officer, ICONIC | Contact Information, Email Address, Phone Number, Budgets and Responsibilities",
"email": "j****#***********.com",
"telephone": "(347) ***-****",
"street_address": "177 East West Colorado Boulevard",
"address_locality": "Pasadena",
"address_region": "CA",
"postal_code": "91195",
"address_country": "USA"
}
*/
You can get the email span via the selector
span[itemprop="email"]
and the postalCode with the same method
span[itemprop="postalCode"]
With those selectors, use querySelector to get to the element, then extract its textContent:
const [email, postalCode] = ['email', 'postalCode'].map(
val => document.querySelector(`span[itemprop="${val}"]`).textContent
);
console.log(email);
console.log(postalCode);
<span itemprop="email">j****#***********.com</span>
<div itemscope="" itemprop="address" itemtype="http://schema.org/PostalAddress">
<span itemprop="streetAddress">177 East West Colorado Boulevard</span>
<span itemprop="addressLocality">Pasadena</span>,
<span itemprop="addressRegion">CA</span>
<span itemprop="postalCode">91195</span>
<span itemprop="addressCountry">USA</span>
I have a javascript object that I would like to traverse and print data based off 1 common category.
Javascript object:
var $states = {
"AL" : {
"longname": "Alabama",
"lawOne": "Alabama Law 1",
"lawTwo": "Alabama Law 2",
"lawThree": "Alabama Law 3",
"region" : "Southeast"
},
"AK" : {
"longname": "Alaska",
"lawOne": "Alaska Law 1",
"lawTwo": "Alaska Law 2",
"lawThree": "Alaska Law 3",
"region" : "Northwest"
},
"AZ" : {
"longname": "Arizona",
"lawOne": "Arizona Law 1",
"lawTwo": "Arizona Law 2",
"lawThree": "Arizona Law 3",
"region" : "Southwest"
},
etc...
}
I am able too loop the array and get as granular as getting the console to log all of the states that are in the same region:
for (var key in $states) {
if ($states.hasOwnProperty(key)) {
var $getStateRegion = $states[key].region
if ($getStateRegion === "Northeast") {
console.log ($states[key].longname);
}
}
}
Once I try to loop through those and print a table with that data is where I am running into an issue. I want to be able to have a withthe 's longname, lawOne, lawTwo, and lawThree values input in there. What gives? Once I try running a for loops through this is where I'm hitting a roadblock. Thanks in advance!
Try the working code below.
var $states = {
"AL" : {
"longname": "Alabama",
"lawOne": "Alabama Law 1",
"lawTwo": "Alabama Law 2",
"lawThree": "Alabama Law 3",
"region" : "Southeast"
},
"AK" : {
"longname": "Alaska",
"lawOne": "Alaska Law 1",
"lawTwo": "Alaska Law 2",
"lawThree": "Alaska Law 3",
"region" : "Northwest"
},
"AZ" : {
"longname": "Arizona",
"lawOne": "Arizona Law 1",
"lawTwo": "Arizona Law 2",
"lawThree": "Arizona Law 3",
"region" : "Southwest"
}
};
var result = {};
Object.keys($states).forEach(function(key) {
if ($states[key]["region"] === "Southwest") {
result[key] = $states[key];
}
});
console.log(result);
You are on the right track. Before I continue, I would like to point out that you are using a for..in loop, but newer versions of Javascript support the for..of loop also, so this is something you may want to consider. The difference is that the for..in loop gives you the keys of the object, and the for..of loop gives you the values, so it shortens the code by skipping the step where you write something to the effect of:
for( var index in array ){
var currentObject = array[ index ];
}
The secret to your solution is in how you handle the DOM, and there are many ways to do this. I will show you one, but it is not necessarily the fastest or the best. I recommend playing around with different DOM manipulations to find the one that works best for you.
First, we know how to get a record, so the javascript aspect of looping, you have that handled...
Next, we need to create the table.... I will assume that you want four columns based on your description, but you could easily adjust this to put the state name and one law on each line, which would probably be a better design allowing a variable number of laws.
The html would look something like this:
<table>
<tr><th>State</th><th>Law 1</th><th>Law 2</th><th>Law 3</th></tr>
<!-- Here is where we would create new html for each state -->
</table>
Your loop then would need to add to this html by creating several lines that appear as:
<tr><td>[State]</td><td>[Law1]</td><td>[Law2]</td><td>[Law3]</td><tr>
We will use string manipulation of the DOM, because it is a good place to start, because it is most similar to what you would write by hand.
We will break the table into three parts: the header, the body and the footer.
var header = "<table><tr><th>State</th><th>Law 1</th><th>Law 2</th><th>Law 3</th></tr>";
var body = ""; //this is where we add the data
var footer = "</table>";
Now, on the loop, we will create each line as needed and add it to the body:
for( var index in stateObj ){
...error checking occurs here...
var state = stateObj[ index ];
var stateColumn = "<td>" + state.longname + "</td>";
var law1Col = "<td>" + state.lawOne + "</td>";
var law2Col = "<td>" + state.lawTwo + "</td>";
var law3Col = "<td>" + state.lawThree + "</td>";
var row = "<tr>" + stateColumn + law1Col + law2Col + law3Col + "</tr>";
//now that we have a row, we add it to the body
body += row; //same as body = body + row;
}
After we have the body, we can make our table by combining the header, body and footer:
var tableHTML = header + body + footer;
And then we find a place to inject it into our document:
var outputDiv = document.getElementById( "stateTableData" );
outputDiv.innerHTML = tableHTML;
Here is a live example:
var states = {
PA: {
longname:"Pennsylvania",
lawOne:"It is illegal to sing in the shower in apartment buildings within the city limits of Philadelphia",
lawTwo:"All motorists are required to stop the vehicle for passing horsemen. The vehicle shall be covered with camoflage so as not to scare the horses.",
lawThree:"Any house having more than four women occupants shall be considered a brothel and shall be in violation of the law."
},
NJ: {
longname:"New Jersey",
lawOne:"There is no such thing as the Mafia",
lawTwo:"Any reference to the denizens of New Jersey shall be derogatory and degrading, think Jersey Shore",
lawThree:"There is no escape from New Jersey and we are not a suburb of NYC"
},
VA: {
longname:"Virginia",
lawOne: "Civil War re-enactments must have the North as the victor.",
lawTwo: "All roads shall end in Richmond, VA",
lawThree: "I have run out of silly ideas for this example."
}
};
function buildTableForState( stateNames ){
var stateList = stateNames.split(",");
//remove spaces
for( var i in stateList ){ stateList[i] = stateList[i].trim(); }
//initialize table parts
var header = "<table><tr><th>State</th><th>Law 1</th><th>Law 2</th><th>Law 3</th></tr>";
var footer = "</table>";
var body = "";
//build body
for( var index in states ){
if( stateList.indexOf( index ) !== -1 ){
var currentState = states[index];
body += buildRowForState( currentState );
}
}
//compose and inject table
var tableHTML = header + body + footer;
var documentOut = document.getElementById( "outputDiv" );
documentOut.innerHTML = tableHTML;
}
function submitTable(value){
buildTableForState( value );
}
function buildRowForState( currentState ){
var state = makeTableCol( currentState.longname );
var law1 = makeTableCol( currentState.lawOne );
var law2 = makeTableCol( currentState.lawTwo );
var law3 = makeTableCol( currentState.lawThree );
var row = makeTableRow( [state, law1, law2, law3] );
return row;
}
function makeTableCol( stringText ){
return "<td>" + stringText + "</td>";
}
function makeTableRow( arrayColumns ){
return "<tr>" + arrayColumns.join("") + "</tr>";
}
<h1>Table Loader</h1>
<form>
<p>Use the values "PA", "NJ", and "VA" to generate a table. You can use more than one value by separating them with a comma.</p>
<input type="text" id="stateNames" name="stateNames" /><br/>
<button onclick="submitTable(stateNames.value);">Build Table</button>
<p>Try:
</p>
<ul>
<li>PA</li>
<li>NJ,VA</li>
<li>VA,PA,NJ</li>
</ul>
</form>
<h1>Table Output appears here</h1>
<div id="outputDiv"></div>
NOTE: Regarding the live code, the HTML is bigger than the display box. In my browser I have to scroll down on the snippit HTML to view the generated table. Either that or expand the snippit window to a full tab to view it in a larger screen.
The above code is simplified, and most coders would tell you not to use HTMLElement.innerHTML, because it is slow, but it is a good place to start. Once you have this down, start practicing with document.create( tagName ), and then use more direct DOM manipulations.
I'm fairly stuck on this, I'm playing catchup on course work.
How do I go about adding values to an array using string from text boxes on the page?
var book = [
{
"name":"Book 1",
"publisher":"Publisher 1",
"isbn":"ISBN 1"
},
{
"name":"Book 2",
"publisher":"Publisher 2",
"isbn":"ISBN 2"
},
{
"name":"Book 3",
"publisher":"Publisher 3",
"isbn":"ISBN 3"
},
];
book.push({"name":"Moby Dick","publisher":"Ryan Spain","isbn":"00147097"});
I know I can push it into the array but I want to add values to name, publisher and isbn from values attained from text boxes in HTML.
EDIT: Adding information
Imagine you have three inputs with the following ids "name", "publisher", "isbn".
var name = document.getElementById('name');
var pub = document.getElementById('publisher');
var isbn = document.getElementById('isbn');
You could add a button when the user is ready to add a book to your list:
<button id="add">Add</button>
var button = document.getElementById('add');
Then you could add an onclick:
button.onclick = function(){
book.push({'name': name.value, 'publisher': pub.value, 'isbn':isbn.value});
}
Getting information:
Is how you would do it.
book[0].name = "Book test";
You could loop through all your books and update them one by one:
for(var i = 0; i < book.length; i++){
book[i].name = "Book " + i;
//etc
}
I currently have an online quiz in the making. The current code works fine, but I would like to see who scored what. I am still extremely new to Javascript, and I have been building this quiz for a friend. I have learned quite a bit just getting this thing to work.
Could someone please point me in the right direction on how to add a simple text input or two that will show up when the results page is called at the end of the questions array
I would like to be able to have the user input their name, and submit it along with the results using the php mailer.
I tried to add a simple html input field like below in the HTML area, but it never produced any results.
<input name="Name" type="text" value="" size="80">
Here is my fiddle to see my setup:
var allQuestions = [{
question: "Anger can be thought of as a like other feelings and emotions.",
choices: ["Emotion", "Wave length", "Continuum", "Exercise"],
correctAnswer: 2
}, {
question: "Strong, silent type of personality will usually when things finally overwhelm him.",
choices: ["Explode", "Implode", "Leave", "Cry"],
correctAnswer: 0
}, {
question: "People that complain about everything, and see themselves as victims, fit the personality type called.",
choices: ["Prosecutor", "Grouch", "Exterminator", "Terminator"],
correctAnswer: 1
}, {
question: "When someone wants to point out the faults in others, in order to shift blame off of himself, he is probably a",
choices: ["Displacer", "Intimidator", "Prosecutor", "grouch"],
correctAnswer: 2
},
{
question: "The type of personality takes his anger out on people or things he views as “less threatening” than the person he is actually mad at.",
choices: ["Grouch", "Displacer", "Prosecutor", "Coward"],
correctAnswer: 1
},
{
question: "The easiest type of anger personality to spot is usually the. Often these types come from abusive backgrounds.",
choices: ["Intimidator", "Grouch", "Displacer", "Prosecutor"],
correctAnswer: 0
},
{
question: "Anger has a medical definition, saying it is an state that ranges from to intense fury and rage.",
choices: ["Mental State Embarrassment", "Emotional State Mild Irritation", "Exhausted State Yawning", "Typical State Relaxing"],
correctAnswer: 1
},
{
question: "Anger is often compared to a",
choices: ["Flock of Geese", "Chord of Wood", "Pressure Cooker", "Bag of Ice"],
correctAnswer: 2
},
{
question: "Anger and rage can become a form of . These people are known as rageaholics.",
choices: ["Addiction", "Skin Disease", "Problem", "Comfort Zone"],
correctAnswer: 0
},
{
question: "First rule When you are don’t say anything!",
choices: ["Right", "Wrong", "Angry", "Confused"],
correctAnswer: 2
},
{
question: "Many times, we feel angry because a situation seems negative, and seems to clash with our.",
choices: ["Belief System", "Current Plans", "Family Members", "Schedule"],
correctAnswer: 0
},
{
question: "Many people carry beliefs, that keep them feeling victimized all of the time.",
choices: ["Stoic", "Unusual", "Irrational", "Western"],
correctAnswer: 2
},
{
question: "To contain anger, all we have to do is learn to view life from a perspective.",
choices: ["Personal", "Different", "Closed", "Unknown"],
correctAnswer: 1
},
];
//you can access checkbox name through an array
//match array number to number in allQuestions array
var questionNum = 0;
var scoreNum = 0;
var makeQuestions = "";
var failedQuestions = [];
$(document).ready(function () {
makeQuestions = function () {
if (questionNum === allQuestions.length) {
$("input[value=SUBMIT]").remove();
$("#questions").text(" All Complete!") .append("<br> Please click the button below to submit your results.") .append("<br>Your score is" + " " + scoreNum);
$("#questions").append("<br><input type='button' id='submit_answers' value='SUBMIT'><br><br>");
$("#answers_correct").val(scoreNum);
$("#questions").append("Failed questions: " + failedQuestions.join());
} else {
$("#questions").text(allQuestions[questionNum].question);
for (var i = 0; i < allQuestions[questionNum]['choices'].length; i++) {
$('#words').append('<input type="radio" name="buttons">' + allQuestions[questionNum]['choices'][i] + '</input');
}
}
}
makeQuestions();
$('#submit_answers').on('click', function () {
$('#answer_submission_form').submit();
});
});
var checkQuestions = function () {
var lenG = document.getElementsByName("buttons").length;
console.log(lenG);
var rightAnswer = allQuestions[questionNum]['correctAnswer'];
for (var i = 0; i < lenG; i++) {
if (document.getElementsByName("buttons")[i].checked === true) {
console.log(i);
console.log(document.getElementsByName("buttons")[i].checked);
//compare value to what was inputted
if (i === rightAnswer) {
scoreNum += 1;
alert("Correct! Your score is" + " " + scoreNum);
} else {
failedQuestions.push(questionNum);
alert("False! Your score is still" + " " + scoreNum);
}
}
}
questionNum = questionNum + 1;
$("#words").empty();
makeQuestions();
}
I'm not sure if this is what you need but I have added a fiddle:
http://jsfiddle.net/5Jjam/40/
I have added a div with the id='name'. This contains an input field for entering your text. This will be shown when all the answers have been submitted.
I have the following JSON:
var questions = {
section: {
"1": question: {
"1": {
"id" : "1a",
"title": "This is question1a"
},
"2": {
"id" : "1b",
"title": "This is question2a"
}
},
"2": question: {
"1": {
"id" : "2a",
"title": "This is question1a"
},
"2": {
"id" : "2b",
"title": "This is question2a"
}
}
}
};
NOTE: JSON changed based on the answers below to support the question better as the original JSON was badly formatted and how it works with the for loop below.
The full JSON will have 8 sections and each section will contain 15 questions.
The idea is that the JS code will read what section to pull out and then one by one pull out the questions from the list. On first load it will pull out the first question and then when the user clicks on of the buttons either option A or B it will then load in the next question until all questions have been pulled and then do a callback.
When the button in the appended list item is clicked it will then add it to the list below called responses with the answer the user gave as a span tag.
This is what I have so far:
function loadQuestion( $section ) {
$.getJSON('questions.json', function (data) {
for (var i = 0; i < data.length; i++) {
var item = data[i];
if (item === $section) {
$('#questions').append('<li id="' + item.section.questions.question.id + '">' + item.section.questions.question.title + ' <button class="btn" data-response="a">A</button><button class="btn" data-response="b">B</button></li>');
}
}
});
}
function addResponse( $id, $title, $response ) {
$('#responses').append('<li id="'+$id+'">'+$title+' <span>'+$response+'</span></li>');
}
$(document).ready(function() {
// should load the first question from the passed section
loadQuestion( $('.section').data('section') );
// add the response to the list and then load in the next question
$('button.btn').live('click', function() {
$id = $(this).parents('li').attr('id');
$title = $(this).parents('li').html();
$response = $(this).data('response');
addResponse( $id, $title, $response );
loadQuestion ( $('.section').data('section') );
});
});
and the HTML for the page (each page is separate HTML page):
<div class="section" data-section="1">
<ul id="questions"></ul>
<ul id="responses"></ul>
</div>
I've become stuck and confused by how to get only the first question from a section and then load in each question consecutively for that section until all have been called and then do a callback to show the section has been completed.
Thanks
Do not have multiple id's in html called "section."
Do not have multiple keys in your JSON on the same level called "section". Keys in JSON on the same level should be unique just as if you are thinking about a key-value hash system. Then you'll actually be able to find the keys. Duplicate JSON keys on the same level is not valid.
One solution can be section1, section2, etc. instead of just section. Don't rely on data-section attribute in your HTML - it's still not good if you have "section" as the duplicate html id's and as duplicate JSON keys.
If you have only one section id in HTML DOM, then in your JSON you must also have just one thing called "section" e.g.:
var whatever = {
"section" : {
"1": {
"question" : {
"1" : {
"id" : "1a",
"title" : "question1a"
},
"2" : {
"id" : "2a",
"title" : "question2a"
}
}
},
"2": {
"question" : {
"1" : {
"id" : "1a",
"title" : "aquestion1a"
},
"2" : {
"id" : "2a",
"title" : "aquestion2a"
}
}
}
}
}
console.log(whatever.section[1].question[1].title); //"question1a"
To get question, do something like this:
function loadQuestions(mySectionNum) {
$.getJSON('whatever.json', function(data){
var layeriwant = data.section[mySectionNum].question;
$.each(layeriwant, function(question, qMeta) {
var desired = '<div id="question-' +
qMeta.id +
'"' +
'>' +
'</div>';
$("#section").append(desired);
var quest = $("#question-" + qMeta.id);
quest.append('<div class="title">' + qMeta.title + '</div>');
//and so on for question content, answer choices, etc.
});
});
}
then something like this to actually get the questions:
function newQuestion(){
var myHTMLSecNum = $("#section").attr('data-section');
loadQuestions(myHTMLSecNum);
}
newQuestion();
//below is an example, to remove and then append new question:
$('#whatevernextbutton').on('click',function(){
var tmp = parseInt($("#section").attr('data-section'));
tmp++;
$("#section").attr('data-section', tmp);
$("#section").find('*').remove();
newQuestion();
});
Technically your getJSON function always retrieves the same data. Your code never compares the id given to the id you're extracting.
Your getJSON should look something like:
function loadQuestion( $section ) {
for (var i = 0; i < questions.section.length; i++) {
var item = questions.section[i];
if (item.id === $section) {
for (var j = 0; j < item.questions.length; j++) {
$('#questions').append('<li id="' +
item.questions[i].id + '">' +
item.questions[i].title +
' <button class="btn" data-response="a">A</button><button class="btn" data-response="b">B</button></li>'
);
}
}
}
}
Modify your JSON to:
var questions = {
section: [{
id: 1,
questions: [{
id: "1a",
title: "This is question1a"
},{
id: "2a",
title: "This is question2a"
}]},{
id: 2,
questions: [{
id: "1a",
title: "This is question1a"
},{
id: "2a"
title: "This is question2a"
}]
}]
};
Edit: your first parameter of getJSON is the URL of the JSON returning service.
You don't need getJSON at all if your JSON is already defined on the client. I have modified the code above.