I've seen a lot of questions about this already, but I'm stumped! Please help!
I have a customvalidator. It's firing but it's not preventing postback. Please help me in doing so! I can see that console.log registers before the post. But, it posts back anyway. How do I prevent the postback?
I've tried adding a control to validate, and validate empty text equal to true. I also tried adding e.preventdefault, which did not work :(
How can I prevent the postback?
<script type="text/javascript">
//<![CDATA[
function validateWhyUnlikely(source, args) {
console.log(1);
args.isValid = false;
}
//]]>
<asp:TextBox ID="txtWhyUnlikely" runat="server" Rows="4" cols="20"
CssClass="surveyTextArea" />
<asp:CustomValidator runat="server" ID="cfvWhyUnlikley" ErrorMessage="Please provide a reason since you rated an item as unlikely to provide."
CssClass="surveyError surveySmallIndent" Display="Dynamic"
ClientValidationFunction="validateWhyUnlikely" />
<asp:Button ID="btnSubmit" runat="server" Text="Submit" CssClass="smallSpecial" OnClick="btnSubmit_Click" />
jQuery(document).ready(function () {
jQuery('#<%= btnSubmit.ClientID %>').click(function (e) {
if (Page.IsValid == false) {
console.log(false);
e.preventDefault();
return false;
}
});
});
Everything looks ok althought I am not sure why you are attaching the Click function to your submit button. I would remove that and test it as it maybe be overriding the default behavior.
Also I think you need to capitalize the IsValid property:
args.IsValid = false;
I too faced this issue, I was trying to add a custom validator to a dropdownlist which had a selectedIndexChange event attached to it. After i gave incorrect value for dropdown, i was able to se ethe error message i gave in Custom Validator but immediately after it Postback was happening.
However on adding this property CausesValidation="true" to the dropdownlist control resolved my issue.
Postback wasn't happening on incorrect value after adding this property to my dropdown.
If it helps other people, I had a Validation group that I forgot to add the button to.
Make sure to add the button, the textbox and the validator to the same validation group for the postback to be prevented.
I experienced this problem as well.
What I did was, in the C# procedure that was called by the button, at the top I added
if (IsValid == false)
return;
I could not stop it performing the postback so this seemed to me like the only solution.
You are misssing ControlToValidate="txtWhyUnlikely"
Posting this as it might help someone that is getting the same weird behavior.
Initially I had the same issue as this post title. I checked all the suggestions here but my code seemed to be fine.
To fix this I replaced my cause validation control <asp:Button.. with a <button.. . Not sure why this is happening but happy it's working now.
hth
<button tags are missing the correct javascript code to validate.
<asp:Button does have the correct javascript rendered.
I've added this to any button tags:
btn.Attributes("onclick") = StringFmt("if(!Page_ClientValidate(''))return false;")
and that solved the post-back issue. No post-back occurs if the client-side detects an issue.
I solved this problem by creating a variable:
Boolean fieldIsValid = true;
and at the custom validating expression I would change the value if arguments weren't true:
if(args.IsValid == false)
{
fieldIsValid = false;
}
else
{
fieldIsValid = true;
}
Then, I also put that in the submit click method:
protected void submit_Click(object sender, EventArgs e)
{
if (fieldIsValid)
{
//submit my things
}
}
Related
In a previous post I asked how to add a bootstrap class to a Data View. The answer was to add the class to the "table.dataview" in a script block. After the table is created the class is applied and all is well.
But when I use a pager the formatting disappears. I am using a partial refresh on the pager to only refresh the data table but doing so means that the bootstrap class does not get applied to the table.
I believe I need to add an event handler that will attach to the refresh action of the dataView to add the class. However I cannot get the event handler to work.
My code for the event handler is below.
<xp:eventHandler refreshMode="partial" submit="true"
id="applyCSS" refreshId="dataView1" event="parialRefresh"
value="what" loaded="false">
<xp:this.binding><![CDATA[#{javascript:"pager1"}]]></xp:this.binding>
<xp:this.action><![CDATA[#{javascript:("table.dataview").addClass("table-striped table-hover table-bordered table-condensed")}]]></xp:this.action>
</xp:eventHandler>
Oliver, the rendered=false was simply a typo - I was testing something and needed to temporarily suppress that.
Oliver and Paul,
Last night I was able to get the partial refresh to work.
I ran across this post by Mark Roden which explained how to do it. There were two different ways to accomplish this, one less and one more efficient. The code I used is below.
<xp:scriptBlock id="scriptBlock3">
<xp:this.value><![CDATA[$('.dataView1PanelWrapper').on("DOMNodeInserted", function(){
$("table.dataview").addClass("table-striped table-hover table-bordered table-condensed")
})]]></xp:this.value>
</xp:scriptBlock>
However, and isn't there almost always a however in Xpages, I have some sortable columns in the view and clicking on the sort brings up the same problem! I lose the class assignment!
So now I would have to intercept that event too, right?
Concerned where this will end. Don't like the idea of DOM Manipulation, and only want to do it if I have too.
I started by using a simple view. It worked great, but for some reason the spacing was messed up in the pagers. I found that by moving the pagers out of the view itself, I was able to get the alignment issue fixed. I think it would be better just to use a view, as I can assign the class directly and won't have to do all this manipulation. It is however very good to know how to do this for the future.
Is that what you would suggest?
==================================================
I have tried Paul Withers suggestion using an output script. This works on the initial page load, but not on any other changes to the data view - when the pager fires, or sorting or any of that. I am close, but no cigar yet. Any suggestions?
<xp:scriptBlock id="scriptBlock5" loaded="false">
<xp:this.value><![CDATA[dojo.require("dojo.behavior");
Behavior = {
".dataview": {
found: function(node) {
dojo.addClass(node,".table-striped table-hover table-bordered table-condensed");
//node.addClass("table-striped table-hover table-bordered table-condensed");
}
}
}
dojo.ready(function() {
dojo.behavior.add(Behavior);
dojo.behavior.apply();
});
//Make sure that future pagers are also straightened out
dojo.subscribe("partialrefresh-complete", null, function(method, form, refreshId) {
dojo.behavior.apply();
});]]></xp:this.value>
</xp:scriptBlock>
Move your existing xp:scriptBlock with the working code inside a facet of the xe:dataView. Then the styling will get applied on initial load and on all partial refreshes.
You should call your CSJS stuff to add the class in the onComplete property of the event handler - hard to find, just highlight the event handler object in source code or outline and then open "All properties" to find the "onComplete" property. This event allows CSJS to be called.
BTW: why is the loaded property = false? The event will never we rendered.
dojo.behavior, dojo.ready and dojo.subscribe should allow you to manage this. dojo.behavior allows you to define a particular behaviour for a particular collection of elements which will be retrieved via a Dojo query. dojo.ready will (I believe) run the code when the page initially loads and dojo.subscribe("partialrefresh-complete", null, function(method, form, refreshId) {...} will run the code aftedr a partial refresh.
Here's sample code I used for converting a DataView's category column images to Font Awesome icons, so the Behavior = {...} bit will need amending.
Behavior = {
// Convert xp:pagers to Bootstrap
".catColumn a img": {
found: function(img_node) {
var imgSrc = dojo.getNodeProp(img_node, "alt").toLowerCase();
if (imgSrc.indexOf("collapse") >= 0) {
dojo.place('<i class="fa fa-minus-square"></i> ', img_node, 'replace');
} else {
dojo.place('<i class="fa fa-plus-square"></i> ', img_node, 'replace');
}
}
}
}
dojo.ready(function() {
dojo.behavior.add(Behavior);
dojo.behavior.apply();
});
//Make sure that future pagers are also straightened out
dojo.subscribe("partialrefresh-complete", null, function(method, form, refreshId) {
dojo.behavior.apply();
});
I have been following this short and sweet tutorial : Integrating google recaptcha
I have made the relevant modifications to my view as shown here:
<div class="form-group" style="margin-left: 7%;">
#Html.Recaptcha("MyKeyGoesHere", CaptchaTheme.Dark)
#Html.ValidationMessage("ReCaptcha")
</div>
My controller looks like this:
[HttpPost]
[ValidateAntiForgeryToken()]
[CaptchaValidator]
public ActionResult SignUp(RegistrationSignUp model, bool captchaValid)
{
if (ModelState.IsValid) // Make sure all fields are field out.
{
}
return View(model);
}
But captchaValid is always false even though I have checked the check box? have I missed something? any help would be appreciated.
Try this;
var response = Request["g-recaptcha-response"];
if (response != null && ReCaptcha.IsValid(response))
{
//
}
I managed to get this working, by diving further into the complete documentation as shown here: Complete integration guide for Google ReCaptcha
I have below code, There can be a case when user types something there is no auto suggestion available, but still i want the text entered by the user.
My onClick function does gets called, but i want to get the value the user has types.
I have tried below approaches, but none seems to be working.
AutoComplete tag
<p:autoComplete id="cityInput"
value="#{myBean.text}"
style="margin-right:15px;"
completeMethod="#{myBean.fetchData}"
global="false"
forceSelection="true"
maxResults="5">
</p:autoComplete>
Button
<p:commandButton id="searchCity"
value="Search"
icon="ui-icon-search"
onclick="captureSearchText();"
action="#{myBean.search}"/>
Script
<script type="text/javascript">
function captureSearchText(){
alert("88");
//var searchVal = myAutoComplete.input.val();
//var searchVal = document.getElementById("cityInput");
//alert(searchVal.value);
//return true;
}
</script>
Edit Section
When I press ENTER key, I get the searched string in my fetchData, maybe because it is p:commandButton. But on click of button also I want to get the searched text. I hope it is clear now. What can I do to get search text on mouse click of search button. tried invoking JavaScript function.
In the completeMethod #{myBean.fetchData} just return the search string as entered by the user if the real 'searching' does not yield any results.
public List<String> fetchData(String query) {
List<String> results = searchService.search(query);
if (results.isEmpty() {
results.add(query);
}
return results;
}
There is in fact nothing 'jsf' to this, plain java creativity.
But the user still has to select it then unless the autocomplete has an autoselect option. Not sure about this. But you can also store the query string in a variable server side and use that if the user does not select anything (setting the field to required is better then imo)
public List<String> fetchData(String query) {
List<String> results = searchService.search(query);
this.queryString = "";
if (results.isEmpty() {
results.add(query);
this.queryString = query
}
return results;
}
Or move it outside the ifEmpty if you always want to store it
forceSelection="true" was an issue actually, it was forcing a selection.
I have removed it and it ran smoothly.
Answer by #Kukeltje is also good, but that is something a workaround, and forceSelection="true" was actually the root cause.
I have a page hosted in 'virtualcasa1' domain opening a modal dialog:
var options = {
title: "Repro",
width: 400,
height: 600,
url: http://domain2:999/sites/blank/_layouts/XDomainTest/XDomainTestTarget.aspx //[1]
//url: http://virtualcasa1/sites/blank/_layouts/XDomainTest/XDomainTestTarget.aspx [2]
};
SP.UI.ModalDialog.showModalDialog(options);
And I have this code to close it:
alert(document.domain);
SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.cancel, 'Cancelled clicked');
If both are in the same domain (case [2] above), the dialog closes well, no issues.
But - if target page hosted in the dialog (case [1] above), dialog does NOT close :-(
document.domain above shows the correct domain where page exists.
I suspect I'm facing a cross-domain issue here (duh), but how to fix it? Or am I wrong and issue is not XDomain-related?
Thanks much!
HTML5's postMessage is your answer.
https://developer.mozilla.org/en-US/docs/Web/API/Window.postMessage
Your parent window that initiates the dialog must have the following javascript:
function listener(event) {
//alert(event.data);
if (event.data == 'Cancel') {
SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.cancel, 'Cancel clicked');
}
else {
SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.OK, event.data);
}
}
if (window.addEventListener) {
addEventListener("message", listener, false)
} else {
attachEvent("onmessage", listener)
}
Javascript for OK and Cancel buttons in your popup:
<input type="button" value="OK" onclick="parent.postMessage('Message to be displayed by the parent', '*');" class="ms-ButtonHeightWidth" />
<input type="button" value="Cancel" onclick="parent.postMessage('Cancel', '*');" class="ms-ButtonHeightWidth" />
Ajay's answer from the 1st of August 2014 is good, but it needs a bit more explanation. The reason for the failure to close the dialog is simple. Cross site scripting security features of modern browsers disallow a few things, one of which is the use of window.frameElement from within the framed window. This is a read-only property on the window object and it becomes set to null (or with IE, it actually throws an exception when you try to access it). The ordinary Cancel event handlers in the modal dialog conclude with a call to window.frameElement.cancelPopup(). This will fail of course. The ordinary Save handler where the Save worked on the server side results in SharePoint sending back a single line as the replacement document, which is a scriptlet to call window.frameElement.commitPopup(). This also will not work, and it's a real pain to overcome because the page has been reloaded and there is no script available to handle anything. XSS won't give us access to the framed DOM from the calling page.
In order to make a cross domain hosted form work seamlessly, you need to add script to both the page that opens the dialog and the framed page. In the page that opens the dialog, you set the message listener as suggested by Ajay. In the framed form page, you need something like below:
(function() {
$(document).ready(function() {
var frameElement = null;
// Try/catch to overcome IE Access Denied exception on window.frameElement
try {
frameElement = window.frameElement;
} catch (Exception) {}
// Determine that the page is hosted in a dialog from a different domain
if (window.parent && !frameElement) {
// Set the correct height for #s4-workspace
var frameHeight = $(window).height();
var ribbonHeight = $('#s4-ribbonrow').height();
$('#s4-workspace').height(frameHeight - ribbonHeight);
// Finds the Save and Cancel buttons and hijacks the onclick
function applyClickHandlers(theDocument) {
$(theDocument).find('input[value="Cancel"]').removeAttr('onclick').on('click', doTheClose);
$(theDocument).find('a[id="Ribbon.ListForm.Edit.Commit.Cancel-Large"]').removeAttr('onclick').removeAttr('href').on('click', doTheClose);
$(theDocument).find('input[value="Save"]').removeAttr('onclick').on('click', doTheCommit);
$(theDocument).find('a[id="Ribbon.ListForm.Edit.Commit.Publish-Large"]').removeAttr('onclick').removeAttr('href').on('click', doTheCommit);
}
// Function to perform onclick for Cancel
function doTheClose(evt) {
evt.preventDefault();
parent.postMessage('Cancel', '*');
}
// Function to perform onclick for Save
function doTheCommit(evt) {
evt.preventDefault();
if (!PreSaveItem()) return false;
var targetName = $('input[value="Save"]').attr('name');
var oldOnSubmit = WebForm_OnSubmit;
WebForm_OnSubmit = function() {
var retVal = oldOnSubmit.call(this);
if (retVal) {
var theForm = $('#aspnetForm');
// not sure whether following line is needed,
// but doesn't hurt
$('#__EVENTTARGET').val(targetName);
var formData = new FormData(theForm[0]);
$.ajax(
{
url: theForm.attr('action'),
data: formData,
cache: false,
contentType: false,
processData: false,
method: 'POST',
type: 'POST', // For jQuery < 1.9
success: function(data, status, transport) {
console.log(arguments);
// hijack the response if it's just script to
// commit the popup (which will break)
if (data.startsWith('<script') &&
data.indexOf('.commitPopup()') > -1)
{
parent.postMessage('OK', '*');
return;
}
// popup not being committed, so actually
// submit the form and replace the page.
theForm.submit();
}
}).fail(function() {
console.log('Ajax post failed.');
console.log(arguments);
});
}
return false;
}
WebForm_DoPostBackWithOptions(
new WebForm_PostBackOptions(targetName,
"",
true,
"",
"",
false,
true)
);
WebForm_OnSubmit = oldOnSubmit;
}
applyClickHandlers(document);
}
});
})();
This solution makes use of the jQuery library, which our organization uses extensively. It is our preferred framework (chosen by me). I'm sure someone very clever could rewrite this without that dependency, but this is a good starting point. I hope someone finds it useful, as it represents a good two days work. Some things to note:
SharePoint does a postback on all sorts of events on the page, including putting the page into edit mode. Because of this, it makes more sense to trap the specific button clicks, both on the form and in the ribbon, rather than wholesale redefinition of, for example, the global WebForm_OnSubmit function. We briefly override that on a Save click and then set it back.
On any Save click event, we defeat the normal posting of the form and replace that with an identical POST request using AJAX. This allows us to discard the returned scriptlet when the form was successfully posted. When the form submission was not successful, perhaps because of blank required values, we just post the form properly to allow the page to be updated. This is fine, since the form will not have been processed. An earlier version of this solution took the resulting HTML document and replaced all of the page contents, but Internet Explorer doesn't like this.
The FormData api allows us to post the form as multipart-mime. This api has at least basic support in all modern browsers, and there are workarounds for older ones.
Another thing that seems to fail in the cross domain hosted dialog is the scrolling of the content window. For whatever reason, the height is not set correctly on the div with id s4-workspace, so we also set that in the solution.
EDIT:
Almost forgot. You may also need to add this control to your framed ASPX page, which can be done with SharePoint Designer:
<WebPartPages:AllowFraming runat="server"/>
I have exactly the same issue - a dialog opening a view page for an item works fine when opened from a site collection on the same web app/domain, but the Close button fails to work when opening the same item from a site collection hosted in a separate web application. I'm assuming it is a cross-domain thing so I've altered the solution to accomodate this restriction, however, I'm not 100% happy about it as it does make the overall solution a little awkward to use from a user-perspective. I've put the issue to one side for now due to project timescales, but I'm still curious as to why. The only things I can think of is the whole cross-domain thing causing it and that maybe it is there by design to prevent XSS security holes.
This seems like it should be pretty straightforward but I'm not feeling it.
I have a JSF CommandButton that executes a long running serverside task (10-15 seconds). I've seen forms where the button context changes after it's been clicked (The label on the button changes and the button becomes disabled until the processing is complete).
I'm using ICEFaces and have the disabled property set to a boolean on the underlying page code.
The action listener bound to the button changes that boolean to disable it but alas, no changes on the JSP.
Anyone?
What you can do is to change the status of the button using Javascript:
<h:commandButton ... onclick="this.disabled=true"/>
Edit regarding the comment:
If the previous code does not submit the form, then you have to disable the button a little time after the click, not "during" the click itself. You can do that using the following code:
<h:commandButton ... onclick="setTimeout('this.disabled=true', 100);"/>
I'm not sure if the fact to use the this keyword directly in the setTimeout method will work correctly. If not, you can use another way to do that:
<h:commandButton ... onclick="disableButton(this.id);"/>
with the following Javascript function:
function disableButton(buttonId) {
setTimeout("subDisableButton(" + buttonId + ")", 100);
}
function subDisableButton(buttonId) {
var obj = document.getElementById(buttonId);
if (obj) {
obj.disabled = true;
}
}
(I'm sure this code can be enhanced, thus)
You should use an ice:commandButton instead of h:commandButton, since it has the partialSubmit property, which will perform the action as an AJAX call. This should refresh your button's state, so if the property on the server has been set to false, your button should be disabled.
do a javascript submit(); first and then disable the button
Similar to the solution from romaintaz
For a Firefox specific solution, the following works (it does not work in IE):
<h:commandButton ... onclick="disableButton(this.id);" />
Using Javascript function:
function disableButton(buttonId) {
var obj = document.getElementById(buttonId);
if (obj) {
setTimeout(function(thisObj) { thisObj.disabled=true; }, 50, obj);
}
}
do it after icefaces has updated the DOM. you can use ice.onAfterUpdate(callback):
Here with jQuery
ice.onAfterUpdate(function(){
updateButtons();
});
function updateButtons(){
if(!isButtonEnabled()){
jQuery(".myButton").attr('disabled', true);
jQuery(".myButton").removeClass("iceCmdBtn").addClass("iceCmdBtn-dis");
}else{
jQuery(".myButton").removeAttr('disabled');
jQuery(".myButton").removeClass("iceCmdBtn-dis").addClass("iceCmdBtn");
}
}