LocalStorage retrieving from arrays, confusion - javascript

Getting confused, creating a web app where people post notes, I have a field for subject and one for the actual note, when posted these should be saved into two arrays, when posted these should appear almost like a comment, with what you just entered in two fields, which did work but I want people to be able to save their notes, close the browser and return, below is the code that is not working, basically the user should be able to
Allow user to enter in values.
If local storage is available, Take values saved from arrays (which I tried converting to a string then convert back to a array using JSON, which is confusing) and fill the page
$("document").ready( function (){
//Each subjectField.value goes into array
var subjectInputArray = [];
//Each noteField.value goes into array
var noteInputArray = [];
//Color array holds color hex codes as values
var noteColourArray = [];
noteColourArray[0] = "#03CEC2";
noteColourArray[1] = "#ADC607";
noteColourArray[2] = "#ffdd00";
noteColourArray[3] = "#f7941f";
//Variable holds properties for note creation
var noteCreate =
{
noteCreateContainer : $("<article>", { id: "noteCreateContainer" }),
noteForm : $("<form>", { id: "noteFormContainer" }),
subjectField : $("<input>", { type: "text", placeholder: "Title", id: "subject"}),
noteField : $("<input>", { type: "text", placeholder: "Write a Note", id: "noteContent" }),
submitNote : $("<button>", { type: "submit", id: "post", text: "post"}).on( "click", (postNote))
}
//Variable holds properties for a note content (NOT SUBJECT);
var notePost = {}
//--------------------------------------------------------------------------------
//Test if local storage is supported
if( Modernizr.localstorage ) {
//Get current array/list
localStorage.getItem("subjectInputArray")
//Convert string back to array
var savedNoteSubjects = JSON.parse(localStorage["subjectInputArray"]);
//For each item in subject localStorage array, loop through an fill page with fields containing values
for(var i = 0; i < savedNoteSubjects.length; i++)
{
//Create container for post
//Apply noteCreateContainer's selected background color to the posted note
$("<article>").appendTo("body").addClass("notePostContainer").css("background-color", ($("#noteCreateContainer").css("background-color")));
console.log("local storage: " + [savedNoteSubjects]);
//Select last div of class notePostContainer to add input field, instead of adding 1+ input fields on each click to all classes using the same class name
$("<input>", {class: "subjectFieldPost", type: "text", value: savedNoteSubjects[savedNoteSubjects.length-1] }).appendTo(".notePostContainer:last-child").prop("disabled", true);
}
} else {
alert("Your browser does not support localStorage, consider upgrading your internet browser");
}
//--------------------------------------------------------------------------------
//Create/Set up fields required for user to input data
noteCreate.noteCreateContainer.prependTo("body");
noteCreate.noteForm.appendTo(noteCreateContainer);
//Loop through noteColourArray and append new button for each item
for (var i = 0, len = noteColourArray.length; i < len; i++) {
noteCreate.noteForm.append($("<button>", {class: "colourSelect", value: noteColourArray[i] }).css("background-color", noteColourArray[i]).click(setBackgroundColour))
}
//Change background colour on click
function setBackgroundColour()
{
$("#noteCreateContainer").css("background-color", noteColourArray[$(this).index()] )
return false;
}
noteCreate.subjectField.appendTo(noteFormContainer);
noteCreate.noteField.appendTo(noteFormContainer);
noteCreate.submitNote.appendTo(noteFormContainer);
//--------------------------------------------------------------------------------BELOW NOTE POST/OUTPUT FROM CREATING NOTE
//FUNCTION - CREATE NEW POST UPON CLICKING POST
function postNote()
{
//Add submitted value of subject field to array
subjectInputArray.push( $("#subject").val() );
//Convert array into string
localStorage["subjectInputArray"] = JSON.stringify(subjectInputArray);
//Add value of note field to array
noteInputArray.push( $("#noteContent").val() );
//Create container for post
$("<article>").appendTo("body").addClass("notePostContainer").css("background-color", ($(noteCreateContainer).css("background-color")) ) //Apply noteCreateContainer's selected background color to the posted note
//Select last div of class notePostContainer to add input field, instead of adding 1+ input fields on each click to all classes using the same class name
//Pull value from local storage subject array
$("<input>", {class: "subjectFieldPost", type: "text", value: subjectInputArray[subjectInputArray.length-1] }).appendTo(".notePostContainer:last-child").prop("disabled", true)
//Select last div of class notePostContainer to add input field, instead of adding 1+ input fields on each click to all classes using the same class name
$("<input>", {class: "noteFieldPost", type: "text", value: noteInputArray[noteInputArray.length-1] }).appendTo(".notePostContainer:last-child").prop("disabled", true)
return false;
} //End function
});
An earlier post I made in relation to my idea
button click temporarily changes div background color, not permanently as intended

var subjectInputArray = [];
...
localStorage["subjectInputArray"] = JSON.stringify(subjectInputArray);
You are setting your localStorage["subjectInputArray"] to an empty array every time your page loads.
How could you expect load anything useful from it?
Instead, try put localStorage["subjectInputArray"] = JSON.stringify(subjectInputArray); in postNote(), so every time user input something, you update the localStorage record.
Additionally,
var savedNoteSubjects = JSON.parse(localStorage["subjectInputArray"]);
this line should be inside the test local storage if block. Don't use it until it's confirmed to be available

Related

Dynamically check javascript value after database update

I am developing a dynamically generated and self updating form in ASP.NET MVC using javavascript, Jquery, JSON/Ajax calls.
Here is how I set up my view code from the controller. I loop through all available controls from the controller:
<ul>
#using (Html.BeginForm("Index", "WebMan", FormMethod.Post)) {
foreach (var row in Model.controls)
{
<li>
<label>#row.Name</label>
#if (row.ControlType == "STRING" || row.ControlType == COMMENT")
{
<input type="text" name="#row.Name" id="#row.NameID" value="#row.Value" data-original-value="#row.Value" class="form-control data-field" style="width: 300px"/>
}
else if (row.ControlType == "DDL")
{
<select name="#row.Name" id="#row.NameID" class="form-control data-field" value="#row.Value" data-original-value="#row.Value" style="width: 300px">
#foreach (var o in row.Options)
{
<option value="#o.Value">#o.Text</option>
}
</select>
}
</li>
}
<button type="submit">Update</button>
}
</ul>
(notice that I set the value to the value from the database and I also set the “data-original-value” to the value from the database as well)
I am using the “data-original-value” to check to see if the value has changed later.
I also set up a javascript timer that executes every 5 seconds. This timer is meant to “update” the page. (code for timer below)
var interval = setInterval(function () { Update(); }, 10000);
When the timer executes, we loop through each control in the “data-field” class. This allows me to check each dynamically generated control.
Basically, If a user has edited a control, I DO NOT want to update that control, I want to ignore it. I only want to update that specific control if a user has not changed the value. When a user changes the value, the current value != orig value (Data-original-value), so we set the field to yellow and ignore the database update code.
function Update() {
UpdateControls();
}
function UpdateControls() {
$(".data-field").each(function () {
var nameAttr = $(this).attr('name');
var id = $(this).attr('id');
var val = document.getElementById(id).value;
var origVal = $(this).data("original-value");
if (origVal == val) {
//user did not change control, update from database
var url = "/WebMan/UpdateControlsFromDB/";
$.ajax({
url: url,
data: { name: nameAttr },
cache: false,
type: "POST",
success: function (data) {
if (data != null) {
document.getElementById(id).setAttribute("data-original-value", data);
document.getElementById(id).value = data;
}
else {
alert(data);
}
},
error: function (response) {
alert("Issue updating the page controls from database");
}
});
}
else {
document.getElementById(id).style.backgroundColor = "yellow";
//user changed control, do not update control and change color
}
});
}
If no change, this ajax method in my controller is called:
[HttpPost]
public ActionResult UpdateControlsFromDB(string name)
{
var curValue= db.Setup.Where(x => x.Name == name).Select(x =>Value).FirstOrDefault();
return Json(curValue);
}
The code works correctly if a user modifies the field. It senses that the user modifies the code, and changes the field yellow.
The part that does not work correctly, is if the database updates the field. When the database first updates the field, it looks great. We set the “data-original-field” value to the value as well, to tell our code that is should not turn yellow and the user has not modified it.
But after another update, “value” and “original-value” do not match. The code document.getElementById(id).value somehow gets the OLD version of the control. It does not get the current value. So then on next loop, the values don’t match and we stop updating from DB and the control turns yellow.
My issue is that my code senses that the control value changed (database update) and turns it yellow, when I only want to turn the control yellow when a USER has changed the value in the control.
I only want to change the control and prevent updating from DB when the control has been modified by the user.
Thank you for any help.

Create JSON from dynamic form generation

I'm creating a dynamic form. Which has drag and drop feature. When Admin has completed the form creation,I have to save form details in Db.
Fiddle link for Form Generation
I don't know from where to start or how to traverse the form to save in json format.
I was to save Json format like this
var formDetails = [
{
"type":"textbox",
"label":"Please enter your name",
"id":"txt-1465133974748"
},
{
"type":"select",
"label":"Please Select Option",
"id":"select-1865133974748",
"fieldOptionDetails":[
{
"fieldLabel":"Option 1",
"fieldValue":"1"
},
{
"fieldLabel":"Option 2",
"fieldValue":"2"
}]
}];
$('#btnSaveForm').on('click',function(){
var formdetail = [];
$("ul#form-Container li").each(function(){
var input = {};// crate an object
// access each form li elements and add the attributes to input object
input.type = "textbox / select"; // depending on your form field type
input.label = "form field label"; // similarly add other fields also
formdetail.push(input) ; // add object to formdetail array
});
JSON.stringify(formdetail); // use josn.stringify(array)
});

How to add multiple input field inside a div dynamically using JavaScript/jQuery?

I need to create some multiple input field dynamically on onkeypress event using JavaScript/jQuery.
I have one text-box,when user is entering any key on that text area two input field and second text-box is opening. When user will enter any key on second text box again another two input field and third text-box will open and so on. There is also a cross button is creating to close each individual set of text-box. In my current code I doing this putting all field static as user may create many numbers of input field so that I want to create those in dynamically with different name and id.
My code is in this Plunkr.
EDIT: Misunderstood question, answer below
This can easily be done if you have a specific field in which to create the input fields. For example, I will load input fields into document.body
Everytime you call newinput() an input field is created in parent who's id starts at input0 and increments each time
var id = 0;
var newinput = function() {
var parent = document.body
var field = document.createElement("input")
field.className = "myclassname"
field.style = "display:block;"
field.id = "input" + id;
parent.appendChild(field);
id += 1;
}
<body>
<div>Click plus to add input</div>
<button type="button" name="button" onclick="newinput()">+</button>
</body>
In your case, it looks like you want to add a group, you can do this:
var fieldgroup = document.querySelector(".questionshowp .form-group").cloneNode(true); // (1)
var addinput = function(){
var parent = this.parentNode.parentNode.parentNode; // (2)
var n = parent.querySelectorAll(".form-control").length
var f = fieldgroup.cloneNode(true);
f.children[0].id = "question"+n // (3)
f.querySelector(".secondsec").querySelector("button.btn-success").onclick = addinput // (4)
parent.insertBefore(f,parent.querySelector(".clear")); // (5)
}
Create a copy of a field-group to be used as a template
Get the container of input fields
Set the input field id with regard to total number of form-groups in parent
Make sure template applies addinput() to button
Insert input form before end of parent form
The easiest way apply this function to all + buttons is with JQuery
$("button.btn-sm.btn-success").on("click", addinput)
This would need to be located at the bottom of your html file, and below addinput() definition
EDIT: Real Answer
Turns out I wrote all that and just realized I misunderstood your question.
Still we can use the same principle to do what I believe you are asking
master = document.querySelector(".aquestionpart"); // (1)
form = document.querySelector(".questionparts"); // (2)
function show(){
var f = form.cloneNode(true);
var n = master.querySelectorAll(".questionparts").length;
f.id = "questionparts"+(n+1); // (3)
f.querySelector("#questions").onkeypress = show; // (4)
this.parentElement.parentElement.querySelector("#questionparts"+ n + " > .questionshowp").style ="display:block;"; // (5)
this.onkeypress = undefined; // (6)
master.insertBefore(f,master.children[master.children.length-1]) // (7)
}
form.querySelector("#questions").onkeypress = show; // (8)
form = form.cloneNode(true); // (9)
Get poll container
Get poll question form to use as template
Set new poll question form id with respect to number of others
Set show function to new poll question
Show multiple choice
Make sure subsequent keypresses dont create more questions
Insert question before .clear
sets up first question to show
creates copy of fresh question to use as template
With this your current scripts.js is unnecessary, and .aquestionpart must look like this for proper formatting
<div class="aquestionpart">
<div class="questionparts" id="questionparts1">...</div>
<div class="clear"></div>
</div>
From within .questionparts be sure to remove onkeypress="show();" from input. It should look like this.
<input name="questions" id="questions" class="form-control" placeholder="Questions" value="" type="text">
And finally an interesting note is that both of the scripts I've provided can be used together! (With some slight modifications)
//Author: Shane Mendez
var fieldgroup = document.querySelector(".questionshowp .form-group").cloneNode(true);
var addinput = function(){
var parent = this.parentNode.parentNode.parentNode;
var n = parent.querySelectorAll(".form-control").length
var f = fieldgroup.cloneNode(true);
f.children[0].id = "question"+n
f.querySelector(".secondsec").querySelector("button.btn-success").onclick = addinput
console.log(parent)
parent.insertBefore(f,parent.children[parent.children.length-1]);
}
master = document.querySelector(".aquestionpart");
form = document.querySelector(".questionparts");
function show(){
var f = form.cloneNode(true);
var n = master.querySelectorAll(".questionparts").length;
f.id = "questionparts"+(n+1);
f.querySelector("#questions").onkeypress = show;
console.log(this)
this.parentElement.parentElement.querySelector("#questionparts"+ n + " > .questionshowp").style ="display:block;";
this.onkeypress = undefined;
master.insertBefore(f,master.children[master.children.length-1])
$(f.querySelectorAll("button.btn-sm.btn-success")).on("click", addinput)
}
form.querySelector("#questions").onkeypress = show;
form = form.cloneNode(true);
$("button.btn-sm.btn-success").on("click", addinput)
If you put this in your scripts.js file and put that at the bottom of your body tag, then the only thing left is the - buttons.
You can use this Press to add multiple input field inside a div dynamically using jQuery. Here you only need to call the function that takes two parameter HTMLElement and config like:
$(".addInput").click(function() {
build_inputs($(this), config);
});
In the config you can add numbers of inputs form config like:
let config = {
title: "Slides",
forms: [
{
type: "text",
name: "name",
class: "form-control mb-2",
placeholder: "Enter Data..."
},
{
type: "file",
name: "image",
class: "btn btn-light btn-sm mb-2 btn-block"
},
{
type: "number",
name: "mobile",
class: "form-control mb-2",
placeholder: "Enter Data..."
}
],
exportTo:$('#getData')
};

jquery get data attributes from dynamically generated options

I am creating a drop down dynamically after an ajax all and populating the fields. I am also calling jquery.data() to set some attribute which I want in future.
HTML
<input id="test" type="text" list="mylist"/>
<datalist id="mylist"></datalist>
JS
$(function() {
// assume this data is coming from ajax call
var data = [{
"name": "John",
"id": 1
}, {
"name": "Jane",
"id": 2
}, {
"name": "Judie",
"id": 3
}];
var generateDropDown = function(data) {
var datalist = $('#mylist');
for (var i = 0; i < data.length; i++) {
var value = data[i].name + ' => ' + data[i].id;
$('<option>', {
'class': 'myclass'
})
.val(value)
.data('extra', {
'newid': data[i] * 100
})
.appendTo(datalist);
}
};
generateDropDown(data);
$('.myclass').on('select', function(selected) {
console.log($(selected).data('extra'));
console.log($(this).data('extra'));
});
});
Here is the JSFiddle
My requirement is to access the selected value from drop down along with the data attribute i have added. How can I do that ?
I tried the 2 console.log options as mentioned above but they dont print anything.
In comparison to HTMLSelectElement object, HTMLDataListElement object doesn't have selectedIndex property, so it seems you have to filter the options for getting the possible selected option.
$('#test').on('change', function (/* event */) {
var val = this.value;
var data = $(this.list.options).filter(function() {
return this.value === val;
}).data('extra');
});
Here is a demo.
Also note that data[i] * 100 results in a NaN (Not a Number) value as you are multiplying an object by a number and it doesn't make any sense!
When using a datalist, think of it as just a list of suggestions for the user. The user can type whatever he/she wants. The option elements are not related to the actual selected value which is stored in the textbox. If you must use a datalist, then use an event on the textbox and select the option based on the value. Something like:
$('#test').on('change', function(selected) {
alert($("#mylist option[value='"+$(this).val()+"']").data('extra'));
});
This takes the textbox value and finds the associated datalist option. However, if I type some random gibberish, it won't and can't work since no corresponding option exists. The alternative is to use a select which forces the user to choose one of the options in the list.
If you want a select, take a look at https://jsfiddle.net/tscxyw5m/
Essentially now we can do:
$("#mylist").on('change', function() {
alert($(this).find("option:selected").data("extra"));
});
Because now the options are actually associated with the select.
Also note I think you meant:
'newid': data[i].id * 100
Not
'newid': data[i] * 100
Which yields NaN.
DEMO: https://jsfiddle.net/erkaner/9yb6km6a/21/
When you try to get the value of the selected item, you need to search through the options in the page and bring the option item that matches with the value in the input field:
$("#test").bind('input', function () {
alert($('body')
.find(
'option[value*="' + $(this).val() + '"]'
).data('extra').newid);
});

Fill a field with a dynamic name in CasperJS

I can succesfully logged in a website and then fill a form and get the results.
Now im trying to do this for anyone who uses my app. The problem is that the form I have to fill has a field name that changes to the number of user.
like this:
casper.thenOpen('http://www.foo.com/index.html', function() {
this.fill('form[action="/cgi-bin/login.cgi"]', { login: user,password:pass }, true);
this.click('input[type="submit"][name="enter"]');
this.wait(5000,function(){
this.capture('eff_ss2.png');
});
});
Everything is fine untill here (I read the login and pass with casper.cli.raw.get();
and then I do this:
this.fill('form[action="../foo.cgi"]', {
'from_city': ori,
'to_city': dest,
'plan_03231': 'whatev',
'aspp_03231': 'whatev'
}, true);
The 03231 will change according to the user who logged in. How can I do this dynamically? I already tried to make:
var plan = 'plan_0'+user;
var obj{}
obj[plan] = 'whatev'
this.fill('form[action="../foo.cgi"]', {
'from_city': ori,
'to_city': dest,
obj,
'aspp_03231': 'whatev'
}, true);
but is not working. Can somebody help me?
In your last snippet you have the id of the user in the user variable, but put an object into an object item place. This is not valid JavaScript. Since the object key is a composite, you need to set it using obj[''+id] = ''; syntax:
var obj = {
'from_city': ori,
'to_city': dest
};
obj['plan_0'+user] = 'whatev';
obj['aspp_0'+user] = 'whatev';
this.fill('form[action="../foo.cgi"]', obj, true);
An easier method where you don't need the explicit user id is simply selecting the form fields based on the beginning of the name attribute using the ^= attribute matcher and casper.fillSelectors:
this.fillSelectors('form[action="../foo.cgi"]', {
'*[name="from_city"]': ori,
'*[name="to_city"]': dest,
'*[name^="plan_0"]': 'whatev'
'*[name^="aspp_0"]': 'whatev'
}, true);

Categories

Resources