I'd really appreciate recommendations on the most efficient way to approach this.
I'm building a simple javascript application which displays a list of records and allows the user to edit a record by clicking an "Edit" link in the records row. The user also can click the "Add" link to pop open a dialog allowing them to add a new record.
Here's a working prototype of this: http://jsfiddle.net/FfRcG/
You'll note if you click "Edit" a dialog pops up with some canned values. And, if you click "Add", a dialog pops up with empty values.
I need help on how to approach two problems
I believe we need to pass our index to our edit dialog and reference the values within the JSON, but I am unsure how to pass the index when the user clicks edit.
It bothers me that the Edit and Add div contents are so similiar (Edit just pre populates the values). I feel like there is a more efficient way of doing this but am at a loss.
Here is my code for reference
$(document).ready( function(){
// Our JSON (This would actually be coming from an AJAX database call)
people = {
"COLUMNS":["DATEMODIFIED", "NAME","AGE"],
"DATA":[
["9/6/2012", "Person 1","32"],
["9/5/2012","Person 2","23"]
]
}
// Here we loop over our JSON and build our HTML (Will refactor to use templating eventually)
members = people.DATA;
var newcontent = '<table width=50%><tr><td>date</td><td>name</td><td>age</td><td></td></tr>';
for(var i=0;i<members.length;i++)
{
newcontent+= '<tr id="member'+i+'"><td>' + members[i][0] + '</td>';
newcontent+= '<td>' + members[i][1] + '</td>';
newcontent+= '<td>' + members[i][2] + '</td>';
newcontent+= '<td><a href="#" class="edit" id=edit'+i+'>Edit</a></td><td>';
}
newcontent += "</table>";
$("#result").html(newcontent);
// Bind a dialog to the edit link
$(".edit").click( function(){
// Trigger our dialog to open
$("#edit").dialog("open");
// Not sure the most efficient way to change our dialog field values
$("#name").val() // ???
alert($());
return false;
});
// Bind a dialog to the add link
$(".edit").click( function(){
// Trigger our dialog to open
$("#add").dialog("open");
return false;
});
// Bind a dialog to our edit DIV
$("#edit").dialog();
// Bind a dialog to our add DIV
$("#add").dialog();
});
And here's the HTML
<h1>People</h1>
Add a new person
<!-- Where results show up -->
<div id="result"></div>
<!--
Here's our edit DIV - I am not clear as to the best way to pass the index in our JSON so that we can reference positions in our array to pre populate the input values.
-->
<div id="edit">
<form>
<p>Name:<br/><input type="text" id="name" value="foo"></p>
<p>Age:<br/><input type="text" id="age" value="33"></p>
<input type="submit" value="Save" id="submitEdit">
</form>
</div>
<!--
Here's our add DIV - This layout is so similiar to our edit dialog. What is the
most efficient way to handle a situation like this?
-->
<div id="add">
<form>
<p>Name:<br/><input type="text" id="name"></p>
<p>Age:<br/><input type="text" id="age"></p>
<input type="submit" value="Save" id="submitEdit">
</form>
</div>
1) Index can be passed via hidden value or by changing the form url. If you use a template for the form you might be able to just fill the form in on the fly and re-render it. If your site is RESTful the url change might be the more appropriate choice.
You may then need to also write a helper for the URL. The helper function will help figure out the appropriate url depending if it is "new" or a "edit". Next you can use "serialize" http://api.jquery.com/serialize/ to grab all the fields in the form and convert it to key-value pair for $.POST if needed.
2) You have 2 options: Try making 1 form, or use a template. If you just have 1 form at the start then your only option is to use .val() to change the form's values.
If you use the template approach you could either just have the template embedded on the page, or you can pull the final form using $.GET on the server. One nice approach might be to use haml or jade as your templating language. You can then mix and match the approaches. By that I mean you can actually create a template tag on your page and load up the template as the page is initially rendered and fill it with just the form partial. You can then use that form on various other pages including just a basic edit page not in a dialog box.
I made some significant edits to your demo with quite a few comments. http://jsfiddle.net/FfRcG/1/
First I remapped data from array of arrays, to array of objects. It's typically a lot easier parsing the html when you can write strings like '<td>'+item.name+'</td>' VS '<td>'+item[5]+'</td>'. It's simpler to read what's what and debug. Getting data from server this way is not a lot more code to add at server.
I added an ID for each member in the original data which will help when communicating with server and storing data. This id is also being added to the edit button as an html data- attribute that is easily read with jQuery data() method ( see fiddle example)
It will likely be easier to not worry about storing data local for now, and simply update server with ajax call every time an add/edit is made. For this reason I set up a row parser to update your edit form when edit button is clciked. Adding classes for each column helps simplify the form update process. My thinking about storing local is it's just one less step for now, and server will stay current with page.
Remember that element ID's must be unique in a page so the duplicates in forms need to be changed.
As for the visuals between the 2 forms, I added title option to dialogs, and changed "save" button text a bit. If you are wondering where css for dialogs comes from, it is set in the "Manage Resources" panel of fiddle and comes from Google CDN.
SOme of these ideas should help. good luck.
Look into using the clone method, and creating it on the fly when the user clicks the add/edit link (if you have more than one edit). You can then set values on the fly by selecting the inputs and setting their val property.
As for passing the id for the edit you can either use a:
<input type="hidden" name="index" value="" />
Or you can add a property to the div like so:
<div id="edit" data-index="1">
and then referencing it with a
$('#edit').click(function() {
$(this).attr('data-index');
});
inside the click handler to grab the id.
I try something about input values. You can use .attr() for change input value. Here working (only calls 1st Person from jSON.) copy http://jsfiddle.net/serkanalgur/zs3tW/
What i added;
// Bind a dialog to the edit link
$(".edit").click( function(){
// Trigger our dialog to open
$("#edit").dialog("open");
$('input#name').attr('value', people.DATA[0][1]); // for name
$('input#age').attr('value', people.DATA[0][2]); // for age. but needed dynamic ids
return false;
});
Related
I have a complex form; within it there's also an 'add more items' link that takes the user to another form-page (independent). What happens at the moment is that when they have edited the main form without saving it and they go to the independent form, when they come back to the main form page they have lost the edits.
<form id="form_1">
[...]
Add something else.
<input type='submit'/>
</form>
add-something-else page:
<form id="form_2">
<input type='submit'/ onsubmit='go_back_to_form_1'>
</form>
Saving everything in sessionStorage would be overkill (I think), and scripts like FormPersistence.js mess about with other functionalities of my form (i.e. Django formset). I have tried to achieve what I want by attaching this function to my 'add something else' button:
$.when(document.forms["form1"].submit()).then(function(){
window.location.pathname = '/add-something-esle/'
})
For some reasons, though, when I go back to form1 I see that the form wasn't saved. How can I achieve what I want?
A <form> is made up of input elements, and you can persist all the <input .../>s to session/local storage and recover them all on page reloads; I remember answering a similar question before; but here is the summary from that answer:
basically you set an event listener on input elements you want (i.e. query selector); make sure they have id (or something similar) unique because we are going to use it as key t store the value;
here is an example:
function persist(event) {
// `id` is used here
sessionStorage.setItem(event.target.id, event.target.value);
}
// you may use a more specific selector;
document.querySelectorAll("form input").forEach((formInput) => {
// `id` also used here for restoring value
formInput.value = localStorage.getItem(formInput.id);
formInput.addEventListener("change", persist);
});
this snippet will persist all <form> tag's inputs values into session storage;
you can also use more specialized selector in .querySelectorAll() to meet your need
Full page reloads clear all form state. You need a way to persist the state between full page reloads. You can use sessionStorage for that.
I am a bit new to mvc razor and building websites (front and backend). The break down is, I need a button that has a value stored in it be sent to the controller/model. Something similar to html boxtextfor. I have tried giving boxtextfor attributes similar to an input submit button, but it doesn't like that. I have tested the button using javascript and it does have the value within each individual button (# of buttons are dynamic based on previous submit).
I have seen posts like this but I am unsure how to add these to my controller or model so my index page can call it. My model is linked to my index page so I guess I could link these methods in my model.
There's no #Html.Button !
(tried this, but it needs to be linked to my model. A simple button doesn't work.)
Looking for a Html.SubmitButton helper that would accept class attributes in MVC3
I currently don't have access to my code in question. The button needs to be an input submit to go to [HTTPPOST]. However, if you need any more information please let me know.
Thank you for your time,
HtmlNooby
I solved it by wrapping a button with the following. This creates binds each individual button with the given item from an array. Kind of acts like a buttonfor if you will.
Foreach item in array{
#using(Html.BeginForm(…)
{
<button class=input value=item>item</button>
}
}
Trying to edit a website with Excel VBA. The edits appear to work, but when I use the save button, nothing is saved. Why isn't updated data, which is visible on the screen, being saved?
This code opens a web page in internet explorer, navigates where I want, fills out data, all which show on the screen, using various methods, such as:
For Each objElement In objElementColl
ExtractedName = objElement.outerHTML
If InStr(ExtractedName, "NewPermit") > 0 Then
objElement.Checked = True
and
Set DropDown = objHTML.getElementById("ProjectFile-AccreditedCertifierId")
DropDown.selectedIndex = 1
or
objHTML.getElementsByName(ElementName)(0).Value = ValueCheck
All work and changes appear on the screen. I click save by using:
Set objElementColl = objHTML.getElementsByClassName("btn")
For Each objElement In objElementColl
ExtractedName = objElement.outerHTML
If InStr(ExtractedName, "click: save, enable:") > 0 Then
objElement.Click
ExtractedName = 1
Exit For
End If
Next
Which runs. The issue is it doesn't save the changes from the three pieces above.
What I have tried
Pause my code and manually click save (same issue)
Pause my code, manually change a checkbox and run the code to save (does save the manual change, but not the coded ones
Pause the code and manually change a box and manually save (only manually changed box is saved)
From above, it appears my save click works, but although the boxes are visibly changed and filled out using the code, there is a gap between the visible and the background.
Some HTML source code. Is what Chrome shows me when Inspecting an element I am changing:
<fieldset>
<legend>Proposal</legend>
<div class="col-xs-12 col-sm-8 col-md-6">
<div class="row">
<div class="col-xs-2 form-group">
<label for="ProjectFile_ProposalLot">Lot</label><input class="form-control" data-bind="textInput: ProjectFile().ProposalLot" maxlength="100" name="ProjectFile-ProposalLot" type="text" />
</div>
<div class="col-xs-2 form-group" data-bind="visible: ProjectFile().StateId() != 7 && ProjectFile().StateId() != 5">
<label data-bind="text: ProjectFile().ProposalDpLabel()"></label>
<input class="form-control" data-bind="textInput: ProjectFile().ProposalDp" maxlength="100" name="ProjectFile-ProposalDp" type="text" />
</div>
I searched the source code for the page. I believe this might be important, but I am not a HTML coder. I have shortened it a bit
var ProjectFileEditViewModel=(function(){__extends(ProjectFileEditViewModel,ViewModel.Model);function ProjectFileEditViewModel(){ProjectFileEditViewModel.__super__.constructor.apply(this,arguments);};ProjectFileEditViewModel.prototype.fields=function(){return {"Id":new ViewModel.NumberField(0),"StateId":new ViewModel.NumberField(0),"DefaultOfficeAddressId":new ViewModel.ObservableField(),"Name":new ViewModel.ObservableField(),"ExistingApprovalDate":new ViewModel.DateField("DD/MM/YYYY"),"ProjectClosed":new ViewModel.ObservableField(),"ProposalAddress":new ViewModel.ObservableChildField(exports.AddressViewModel,this),"Zoning":new ViewModel.ObservableField(),"ProposalLot":new return ProjectFileEditViewModel;})();if(exports.ProjectFileEditViewModel==null)exports.ProjectFileEditViewModel=ProjectFileEditViewModel;
There is also this:
Buildaform.model=new Buildaform.ProjectPageViewModel({ ... ,"ProposalLot":null .... }
I think this last one has something to do with it. I do not know if I can change it.
I cannot release the website address or source code publicly.
As the regarding web site can not be shared, I can come up with a just set of hints to try out:
If the web site would implement a simple (pure) HTML form to send the POST request, your solution would be fine. But looking at the HTML you shared
<label data-bind="text: ProjectFile().ProposalDpLabel()"></label>
the data-bind is already suggesting that the data is getting collected/sent by a library. (E.g. Knockout is using that attribute). This library might now collect the data somewhere, and it might get triggered by a "click" or a "key" event in JavaScript. The collected information can then be stored in a hidden DOM element as suggested by GCSDC or directly in a JavaScript variable.
What I would suggest now is to find out which JavaScript framework is used on this page by inspecting the HTML source. At some point there should be a
<script src="<fancy js framework>.js"></script>
tag in the HTML, which should give you the name of the framework. (There can actually be multiple tags of this kind, including custom JavaScript files. These tags do not have to be at the beginning of the HTML document, and can be scattered all over it, so you might have to search for script in the HTML document. One of them should be the main framework, which is sending the request. If you are not sure which one it would be, you have to google all of them and find out.)
Then, research how the the POST (maybe Ajax) request is sent in the JavaScript code on this page, with help from the documentation of the Framework. And then, send the request by executing custom JavaScript from VBA on this page; how this could be done is shown in this post.
Alternatively, you could try to trigger a click (or key) event on the form inputs to make the framework believe you actually typed it in; how this could be done is shown in this post, but this might not work in all cases.
Per your comment that:
Pause my code, manually change a checkbox and run the code to save
(does save the manual change, but not the coded ones
It seems that the problem is with the code setting form controls and not with the code clicking the save button.
This seems to be a problem not related to VBA but with the behaviour of knockout - see this SO post. The pertinent comment is:
Your problem is that ko subscribes on the click event inside the checked binding:
The questioner in that post is having a similar problem to you - they are trying to check a checkbox (to change the view) but it is not updating either the viewmodel, or the underlying model itself. Knockout is a MVVM framework.
The give-away in your question is that your manual changes commit because you perform a click-and-change when performing the action via point-and-click in the browser, but your programmatic method only does the change to the form control, but not the click first.
So, how to solve this via VBA automation through IE?
Based on the solution in the post I referenced above, plus the method here I will hazard the code below as a possible solution, but please note it is untested ...
Basically you need to 'click' on the form element you want to change - and then update the control value. Hopefully the 'clicking' bit will mean that the knockout viewmodel updates per the 'change', and from there, the model data will be written to the database (or whatever):
Your checkbox example:
If InStr(ExtractedName, "NewPermit") > 0 Then
// hopefully this will get knockout to apply the required binding before your change the value
objElement.Click
objElement.Checked = True
Your dropdown example:
Set DropDown = objHTML.getElementById("ProjectFile-AccreditedCertifierId")
// hopefully this will get knockout to apply the required binding before your change the value
Dropdown.Click
DropDown.selectedIndex = 1
Hope that helps - quite the 3-pipe problem! Good luck.
I hope this question has an obvious answer to anyone who knows his way around JS and HTML :)
I have a very specific problem. I am trying to add to the header on a site buttons that will function like 'quick searches' which will basically on click send pre-filled form values to my search page and have the search page also populate these values in the ajax form inside.
Here is a sample search page that's outside of the results page:
http://www.thediamondsexperts.com/index.php?route=product/diamondsearch/jewelry
You'll notice that when you change the values there and click Search, the values also appear in the ajax form on the sidebar of the search results page.
What I simply want to do is create different variations for pre-set searches, and put them as buttons in the header.
When I try to put a few invisible forms in it won't work because of the multiple form values with the same ids but in general I think there must be a simple way to do this server side.
For instance, copy the current function that accepts the search, have it with pre-set values instead of populating the values from the form and then simply calling that function onClick. Does that make sense?
I need to create something simple enough though that would be easy for the admin to later change and customize more buttons so a client-side solution would be best.
Your help is much appreciated!
All you need is a form with hidden inputs and a submit button:
<form>
<input type="hidden" name="param1" value="Predefined value 1" />
<input type="hidden" name="param2" value="Predefined value 2" />
<input type="hidden" name="param3" value="Predefined value 3" />
<button type="submit">Search!</button>
</form>
This will only show the button, but the values will still be sent to your form's action.
...there must be a simple way to do this
server side
...a client-side solution would be best
...copy the current function that accepts
the search, have it with pre-set
values instead of populating the
values from the form and then simply
calling that function onClick. Does
that make sense?
Not really, not to me at least. If you can clarify I'd be glad to help more.
When you say "multiple form values with the same ids", I fear you may be confused: There is no requirement for a form input to have an "id", I think you mean "name", and there's no need to have multiple inputs with the same name in a form unless you want to send an array of values.
I didn't want to go overboard and talk about how the ajax works on that site, because that's another thing altogether and all you seemed to be concerned about was the preset search buttons. Hopefully this helps you figure it out, GL.
EDIT: I'm having a tough time figuring out what you're really asking, if you are trying to duplicate the behavior on that site, please tell us what server side language is available to you, if you're using or open to using any javascript libraries, and what you have tried so far. A full fledged spoon-feeding tutorial is really out of scope, you will get better, clearer help if you share the code from your current attempts.
If you want to pass values from one page to another and handle it client-side, use "get" for the form submit method, and use the handy "gup()" function to grab the param values. You can get more info on gup() here:
function gup( name )
{
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\?&]"+name+"=([^&#]*)";
var regex = new RegExp( regexS );
var results = regex.exec( window.location.href );
if( results == null )
return "";
else
return results[1];
}
On your initial page, you can either use inputs with type="hidden" or just get the values from the visible inputs (as on your sample page). Then submit to your results page. Given an initial page with something like this...
<form method="get" action="results.html">
<input type="text" name="caratFrom" value="0.7" />
<input type="submit"/>
</form>
... here's sample usage for the results page:
var caratFrom = gup('caratFrom');
// etc.
Then simply assign those values to whatever elements you want, e.g. an input:
<!-- HTML -->
<input type="text" name="caratFromResult" value="" />
// Javascript
document.getElementById('caratFromResult').value = caratFrom;
I have an issue regarding sending form values to a script. I have a form set up, and upon the user pressing a button I want the values in the form to display on another part of the page. I can easily do this with php or another web scripting language, but all I know is how to do this by sending it to the script in a form of
http://www.example.com/myScript.pbp?value1=VALUE
is there a way to do this without loading a new page? Like just show a loading overlay on the page until the script completes and displays the value on the page?
I'm guessing this would be accomplished using Javascript or Ajax or something like that.
If anyone could help me out, or even just say where I should start to look, I'd really appreciate it!
Indeed. Just attach an onsubmit event listener to your form that always returns false to prevent actual sending of your form via the usual GET or POST request.
In your event listener you can send the form values using XMLHttpRequest and let the callback function update the relevant part(s) of your page.
But remember to always create a fallback option (with the usual GET or POST request of the form) to handle your form in case JavaScript is not available (e.g., turned off, blocked, etc.).
Yes AJAX would be exactly how you would do it. Have a look at the tutorial over at Tizag: http://www.tizag.com/ajaxTutorial/index.php
That will get you started in no time at all.
If you just want the values in the form to display on the page again without any interaction with the server then something like jQuery would be the best approach.
Jquery has a nice form plugin that you can do the following:
var form_values = $('#form_name').formHash();
the form_values will then be a hashed array of your form values in the system i.e.
<form id="test">
<input id="test1" name="test1" type="text" value="Test Text"/>
</form>
So form_values['test1'] would hold the value Test Text in it
Once you have the values you could then use some other jquery functions to display them on the page i.e.
<div id="displayDiv"></div>
then your javascript could be
for (key in form_values) {
$('div#displayDiv').append('<div>Key: ' + key + ' Value: ' + form_values[key] + '</div>');
}
This would put your values in the display div
Here is a simple javascript ajax object. You can use without loading any library.