I'm trying to implement client-side input validation for a datatables-editor that I'm rewriting. The form is created dynamically and then added to a bootstrap-modal.
I have encountered a problem where adding <pattern> and/or required doesn't result in any added functionality at all. The form just accepts the input and submits, and I'm quite confused as to why that is.
EDIT:
I have added the relevant code to a plunkr
I have now added the full project. Specifically the issue is connected to the _openEditModal function and _openAddModal function, where i generate the forms dynamically and add the pattern='patternVariable'.
The pattern for this example (however it doesn't work no matter what pattern I use):
^[a-zA-Z0-9\.]+$
Creating the form:
var data = "";
data += "<form name='altEditor-form' role='form'>";
for(var j = 0; j < columnDefs.length; j++){
data += "<div class='form-group'><div class='col-sm-3 col-md-3 col-lg-3 text-right' style='padding-top:7px;'><label for='" + columnDefs[j].title + "'>" + columnDefs[j].title + ":</label></div><div class='col-sm-9 col-md-9 col-lg-9'>";
if(columnTypes[j].type.includes("text")){
data += "<input type='" + columnTypes[j].type + "' id='" + columnDefs[j].title + "' pattern='" + columnPattern[j].pattern + "' title='" + patternErrMsg[j].msg + "' required name='" + columnDefs[j].title + "' placeholder='" + columnDefs[j].title + "' style='overflow:hidden' class='form-control form-control-sm' value='" + adata.data()[0][newaData[j].name] + "'>";
}
if(...){...}
data +="</div><div style='clear:both;'></div></div>";
}
data += "</form>";
As you can see I add the tags like so:
pattern='" + columnPattern[j].pattern + "' title='" + patternErrMsg[j].msg + "' required ...
The modal:
$('#altEditor-modal').on('show.bs.modal', function() {
$('#altEditor-modal').find('.modal-title').html('Edit Record');
$('#altEditor-modal').find('.modal-body').html(data);
$('#altEditor-modal').find('.modal-footer').html("<button type='button' data-content='remove' class='btn btn-default' data-dismiss='modal'>Close</button>\
<input type='submit' data-content='remove' class='btn btn-primary' id='editRowBtn'>Save Changes</input>");
I made sure that the button has type='submit' as I've read that this is what triggers the pattern-check.
editRowBtn code:
$(document).on('click', '#editRowBtn', function(e)
{
e.preventDefault();
e.stopPropagation();
that._editRowData();
});
To make sure that my code is actually adding the attributes to the input i checked the console:
Any help or advice is greatly appreciated as I'm kinda stuck here.
It's a little hard to read your examples (a plunkr would be nice :) ), but from what I can see, you've put your submit button outside your form.
That won't work, since the button won't know what it's submitting.
Try putting the submit button inside the form.
Alternatively, try using the form attribute on the submit button, which should reference the form ID. I've never used this myself, but according to MDN, it's part of the HTML5 spec.
Form attribute description from MDN:
The form element that the input element is associated with (its form owner). The value of the attribute must be an id of a element in the same document. If this attribute is not specified, this element must be a descendant of a element. This attribute enables you to place elements anywhere within a document, not just as descendants of their form elements. An input can only be associated with one form.
Related
My code generates a table with a button at the end of each row. When the user clicks a button how can I pass a property u.userEmail to the controller via the button? Will the value being sent to the controller be a string?
My (non-working) attempt:
<script>
$(document.body).append("waiting on async table to load<br>");
$(document).ready(function () {
$.getJSON("/Account/LoadClaimsTable", function (crewResponse) {
//returns a List<UserClaims>
$(document.body).append("<table>")
crewResponse.forEach(function (u) {
var s = "";
s+="<tr><td>" + u.userEmail + "</td>";
u.userClaims.forEach(function (k) {
console.log("added claim"+k.value);
s += ("<td>" + k.type + "</td><td>" + k.value + "</td><td>" +
"<input type=\"hidden\" name=\"userEmail\" value=\"`${u.userEmail}`\" />"+
"<input type=\"button\" value=\"Create\" onclick=\"location.href='#Url.Action("EditClaims", "Account")'" />
+"</td>");
});
s += "</tr>";
$(document.body).append(s);
s = "";
});
$(document.body).append("</table>")
});
});
</script>
AccountController.cs contains:
public ActionResult EditClaims(string userEmail)
{
return View("StringView", userEmail);
}
You have to pass it on the url of the action. Not sure if you want to pass u.userEmail, but it could looks like this:
crewResponse.forEach(function (u) {
var s = "<tr><td>" + u.userEmail + "</td>";
u.userClaims.forEach(function (k) {
console.log("added claim"+k.value);
s += ("<td>" + k.type + "</td><td>" + k.value + "</td><td>" +
"<input type=\"hidden\" name=\"userEmail\" value=\"`${u.userEmail}`\" />"+
"<input type=\"button\" value=\"Create\" onclick=\"location.href='#Url.Action("EditClaims", "Account")?userEmail=" + u.userEmail + "'\"/></td>");
});
s += "</tr>";
$(document.body).append(s);
});
There are multiple ways to do it. One is mentioned in the answer above by Felipe. Here is another alternate approach using unobtrusive js
Add the email as html5 data attributes to the button along with another attribute which we will use bind the click behavior.
u.userClaims.forEach(function (k) {
// Add quotes as needed if you want multiline ( i just removed those)
s += "<td>" + k.type + "</td><td>" + k.value + "</td><td>
<input type='button'
clickablebutton data-email='" + u.email + "' value='Create'/></td>";
});
Now, in your document ready, bind a click event handler to those elements (with our custom attribute) and read the data attribute and build the url you need.
$(document).on("click", "input[clickablebutton]", function (e){
var url = '#Url.Action("EditClaims", "Accounts")?useremail=' + $(this).data("email");
window.location.href = url;
});
Some other suggestions
Use the appropriate element. Button is better than input (Consider accessibility)
If it is for navigation, Use an anchor tag instead of a button.
Inline javascript is not great. Let the browser parses your markup without any interruptions and you can add the behavior scripts later (that is the whole point of uobutrisive js approach)
The approach you appear to be taking would be Ajax, response, render a template. With that being said, you may want to rethink your approach.
Step 1.
Build a template
<template id="...">
<button type="button" value="[action]" onclick="[url]">[text]</button>
</template>
Step 2.
Create your request.
axios.get('...').then((response) => {
// Retrieve template.
// Replace bracket with response object model data.
html += template.replace('[action]', response.action);
});
Step 3.
Have the JavaScript render your template.
The above can create a clear concise codebase that is easier to maintain and scale as the scope changes, rather than an individual request performing a change with embedded markup. This approach has worked quite well for me, also I feel it'll make you troubleshooting and definition easier, as the controller is handing an object back to your JavaScript instead of a markup / view data. Which will be a better finite control for the frontend and clear modifications in future.
I am perform add ,edit and delete operation using jquery.
i have create product.html file and jsproduct.js file.
My Question is i am click edit button and change selectbox value and press edit
product button
but select box value can not display table
<script async src="//jsfiddle.net/kishankakadiya/m6sn39hp/1/embed/"></script>
Check Demo
The problem is that you are using the same id for the <td>elements on your table. You are using the counter with this and the result is having more than one <td id="1"> and jQuery will not handle it correctly.
I changed your td's to use a class instead of id and added a class prefix to your td's like this:
'<td class="category-' + this.counter + ' ">' + product_category +'</td>'
'<td class="name-' + this.counter + '">' + product_name + '</td>'
And in your edit function I used the class as a selector:
$(".category-" + this.id).text(product_category);
$('.name-' + this.id).text(product_name);
Then it works correctly. You still have some trouble in setting your mode etc but hopefully you can get those fixed by yourself.
Fiddle: https://jsfiddle.net/ye6mugxe/1/
I have the following Javascript to generate a silent call to another sheet to update a database value without refreshing the page
function UpdateDB(table,column,type){
var value = $("#Assigned").val();
$.post("UpdateValuation.php?Table=" + table + "&Value=" + value + "&Column=" + column + "&Type=" + type, {}).done();
};
This works perfectly but only for the "Assigned" table row since it is statically assigned.
I use the following php to generate the table entry with button
print "<tr><td>" . $stuff['Status'] . "</td><td ><input type=\"text\" id=\"" . $stuff['Status'] . "\" name=\"" . $stuff['Status'] . "\" value=". $stuff['Value'] ." size = \"4\" style = \"text-align: center\"/><button onclick=\"UpdateDB('NOCstatus','Status','". $stuff['Status'] ."');\">Update</button></td></tr>";
Which after variables are assigned looks like this for my "Pending" row
<input id="Pending" type="text" style="text-align: center" size="4" value="120" name="Pending"> </input>
<button onclick="UpdateDB('NOCstatus','Status','Pending');">
Update
</button>
My problem is that passing "this.value" or trying to use a variable in the javascript portion I always come up with a blank value, the only time I can get a value to be correct is by statically assigning the "#Assigned" or "#Pending" in the value field. I have hundreds of entries so I don't want to write the function over for each of these. I know there is probably something extremely simple I am missing but I cannot get the pieces to fit.
I need to pass the typed in value in the input field to the function to update the database. Please help.
function UpdateDB(table,column,type){
var value = $('#'+type).val();
$.post("UpdateValuation.php?Table=" + table + "&Value=" + value + "&Column=" + column + "&Type=" + type, {}).done();
};
?
I have difficulties to edit in form dynamically added rows. For example if some of the cell in the row have error - clicking on it will feed the form with selected row. Hope I'm clear.
Here is a code:
(document).ready(function(){
$("#inputtitle").append("<input type='text' name='type1' placeholder='Title'/><br>");
$("#inputremarks").append("<input type='text' name='type2' placeholder='Remarks'/><br>");
$("#inputdate").append("<input type='text' name='type3' placeholder='Date'/><br>");
$("#inputoption").append("<input type='text' name='type4' placeholder='Option'/><br>");
});
$("form").submit(function(e){
e.preventDefault();
var newName = $('form').find('input[name="type1"]').val();
var newName1 = $('form').find('input[name="type2"]').val();
var newName2 = $('form').find('input[name="type3"]').val();
var newName3 = $('form').find('input[name="type4"]').val();
$('table').append('<tr><td>' + newName + '</td><td>' + newName1 + '</td><td>' + newName2 + '</td><td>' + newName3 + '</td></tr>' );
});
Sorry for being not clear. My question was how to feed back the form when click to one of the new created row. Below is updated JSFiddle with approximate solution, but not correct, because probably need another button with name UPDATE and may be need another column with ID. DEMO.
I desided to go by different way. So I created additional button to run a script for editing cell of created table. The link to the code you can find [here] Using jQuery to edit individual table cells
I know that there's lot here on already on multiple click events being fired off, I think I've read them all but still can't see what's going wrong here.
Hope fully I'm missing something obvious that someone else can pick up easily...
Some background
My code works inside an Enterprise Social Networking platform and creates a BI dashboard for content analysis (about a 1000 lines of the stuff, mostly domain specific, so too much to post in it's entirety).
The part that is causing me grief is the function that builds the dashboard visualisation itself.
Here goes...
function makePage(){
$("#policyCount").text(policyCount);
var docTypes=getGlobalDocTypes(polOwners); //returns a constrained vocab array
var statusTypes=getGlobalStatusTypes(polOwners); //returns a constrained vocab array
$.each(polOwners,function(){ // polOwners is a global array that contains the BI data to be visualised
html=""
var ownerName = this.name.split(":")[1]; // name is a str in format "Owner:HR"
html += "<div id='" + ownerName + "' class='ownerData'>";
html += "<div class='ownerHeading'>" + ownerName + "</div>";
html += this.policies.length + " Policy documents maintained<br />"; // policies is an array of docs managed by owner
divIDReview = "dboard_" + ownerName + "reviewchart";
html += "<div id='" + divIDReview + "' class='dboardelement'></div>";
divIDType = "dboard_" + ownerName + "typechart";
html += "<div id='" + divIDType + "' class='dboardelement'></div>";
divIDStatus = "dboard_" + ownerName + "statuschart";
html += "<div id='" + divIDStatus + "' class='dboardelement'></div>";
html += "<div id='" + ownerName + "ToggleTable' class='toggletable' owner='" + ownerName + "'>";
html += "Click to display all " + ownerName + " documents<br /></div>";
html += "<div id='" + ownerName + "polTable' class='poltable'>";
html += getPolTable(this.policies); // Returns an HTML table of doc metadata
html += "</div>";
html += "</div>";
$("#owners").append(html); // When this function is called #owners is an empty div
$(".toggletable").mouseover(function(){
$(this).css({'cursor':'pointer','text-decoration':'underline'});
});
$(".toggletable").mouseout(function(){
$(this).css( {'cursor':'default','text-decoration':'none'});
});
$(".toggletable").each(function(i, elem){
$(elem).click(function(){
if ($(this).next(".poltable").css("display")=="none"){
// Currently hidden - so show
if (debug){console.log($(this).attr("id") + " was clicked")}
$(this).html("Click to hide " + $(this).attr('owner') + " documents<br/>");
$(this).next(".poltable").css("display","block");
} else {
if (debug){console.log($(this).attr("id") + " was clicked")}
$(this).html("Click to display all " + $(this).attr('owner') + " documents<br />");
$(this).next(".poltable").css("display","none");
}
});
});
// the next section calls functions that use the Google vis api to draw pie charts
drawPie(300,200, "Review Status", "Status", "Policies", getReviewStatus(this.policies), ["green","orange","red"], divIDReview);
drawPie(300,200, "Document Types", "Type", "Docs", getDocTypes(this.policies, docTypes), [], divIDType);
drawPie(300,200, "Document Status", "Status", "Docs", getStatusTypes(this.policies, statusTypes), [], divIDStatus);
});
}
Hopefully that's enough to illustrate the problem.
You'll see that the code builds a dashboard display for each polOwner consisting of three pie charts and an option to hide or display a table of underlying data.
I started by applying the click event to the .toggletable class. When that fired multiple times I used the method described on another answer here with the .each to attach a unique event to each instance of the class.
So, what happens?
There are currently 9 polOwners and at first glance, the click event only seems to be toggling the display state of every other table. The console log however shows that this is because it is firing 9 times for the first instance, 8 for the second, 7 for the third etc. with the odd numbers leaving the table in the alternate state (when this works the display will change to a .toggle animation).
For info, While I'm a text editor person, I do have a copy of MS Expression Web 4 which is a useful tool for error checking HTML. I've pasted in a copy of the entire generated markup (nearly 4000 lines) and can't see any bad nesting or structure errors.
Any ideas folks?
You've got some nested loops:
// jQuery each on polOwners
$.each(polOwners,function(){
// ... code that appends .toggletable class
// jQuery each on .toggletable class
$(".toggletable").each(function(i, elem){
// code that runs on the toggletable element
});
});
For each polOwner you are adding a div with the toggletable class. Then inside there you are looping through each div with a toggletable class and adding a click event.
This adds 1 click for the first polOwner, 2 for the second, three for the third and so on.
Move the toggletable each outside of the polOwner each and you should be good