webix: Validating edits from datatable on the server - webix

I have the following scenario:
An datatable with some editable columns which validate for input on the client with the webix rules. There are columns though, that cannot be validated on the client, but on the server only (ie for unique id/code).
An approach would be to create a rule and validate with webix.ajax in synchronous mode that I would prefer to avoid this at all means.
I thought I could validate on 'save'. The server can return a status response with error or success. I can catch this with onAfterUpdate event of the datatable (correct me if there is a better way, but it works this way).
At this point, I would like to display a validation error on the datatable if the server script returns an error status and mark the row (and possibly the corresponding column/cell) with error.
I thought I could use the callEvent method on the datatable and fire a onValidationError event but I didn't manage to make that work.
save: {
url: "save.php",
autoupdate: true,
on:{
onAfterUpdate:function(response, id, details) {
if (response.status == 'error')
myDataTable.callEvent('onValidationError');
}
}
}
The documentation states that I can pass some parameters to the event from callEvent but I could not find any specification on the docs. The code above does not work (the event is not fired).
So the question is: How can I fire a onValidationError event for the datatable using callEvent?
or what would be another approach to use webix to show the error on the datatable with validation on the server side?
Thank you.

Instead of calleing onValidationError event you can use
//mark cell, call after error response
myDataTable.addCellCss(id, columnId, "webix_invalid");
//remove mark, call after success response
myDataTable.removeRowCss(id, "webix_invalid");
which will mark the cell as non-valid.
On a side note, if you want to trigger some event with parameters, you can use code like next. Just beware that triggering an event is not a good way to change the component's state ( it can be used to trigger your own event handler though )
myDataTable.callEvent("event name", [param1, param2, param3])
just

Related

Microsoft Graph API: "responseRequested" Attribute in "Update Event" does not work

As written in Microsoft Graph documentation, Event update endpoint allows responseRequested as one of the input property. It says:
Set to true if the sender would like a response when the event is
accepted or declined.
I tried setting it to false and I'm expecting it to have similar behavior with "Request responses" button in the UI. Unfortunately, it does not work as I'm expecting it to behave.
For example, in the web UI, if you turn "Request responses" off, no notification will be sent to the attendees and a message that shows no attendance response is required.
UI Screenshot
UI Screenshot - Expected behavior
For the code itself:
type UpdateEventRequest struct {
ResponseRequested bool `json:"responseRequested,omitempty"`
End *DateTimeTimeZone `json:"end,omitempty"`
}
type DateTimeTimeZone struct {
DateTime string `json:"dateTime,omitempty"`
TimeZone string `json:"timeZone,omitempty"`
}
func NewDateTimeTimeZone(t time.Time) *DateTimeTimeZone {
return &DateTimeTimeZone{
DateTime: t.Format("2006-01-02T15:04:05.999999"),
TimeZone: t.Location().String(),
}
}
When I tried to update an event to the following:
&UpdateEventRequest{
ResponseRequested: false,
End: NewDateTimeTimeZone(newEventEndTime),
}
Event end time is updated properly to newEventEndTime. However, ResponseRequested doesn't seem to update anything.
Am I missing something here? My initial goal is to change event end time via API without requiring attendance to submit "Yes/No" response. Thanks.

$batch request resulting in error "Default changeset implementation allows only one operation"

I am making a worklist application using SAPUI5. The problem is that when I create an entry and then create another one right after that, I get the following error:
Default changeset implementation allows only one operation.
I checked the $batch header and I see that there is a MERGE and a POST, with the MERGE updating the previous entry for some reason. Can anyone shed some light? Could it be a backend error and not a UI5 error?
Creating the new entry:
_onMetadataLoaded: function() {
var oModel = this.getView().getModel();
var that = this;
// ...
oModel.read("/USERS_SET", {
success: function(oData) {
var oProperties = {
Qmnum: "0",
Otherstuff: "cool"
};
that._oContext = that._oView.getModel().createEntry("/ENTITYSET", {
properties: oProperties
});
that.getView().setBindingContext(that._oContext);
// ...
}
});
},
handleSavePress: function(oEvent) {
// ...
this.getView().getModel().submitChanges({
success: function(oData) {
// ...
},
error: function(oError) {
// ...
}
});
},
tl-dr: Apparently you must be using the SAP Gateway. If you do not need to process those requests in one transaction then send them in different changesets. If you do not need batch calls at all consider turning it off by supplying your model with "useBatch": false upon instantiation. However if you need to process the requests together in one transaction then you have to read the details below.
In order to understand the problem you have to understand how the gateway and the batch and changeset requests work.
Batch requests consist of multiple requests bundled together. The purpose is to open only one connection and group together relevant requests so that the overhead is minimalized. Changesets form smaller blocks inside batch requests, where modification requests can be bundled and processed together in order to ensure an all-or-nothing characteristic.
So on the gateway side: there are two relevant classes for your OData service, assuming that you have used the SAP Gateway Service Builder (SEGW transaction). There is one with the ending ...DPC and one with ...DPC_EXT. Don't touch the former, it will be always regenerated when you update your service in the service builder. The latter is the one that we will need in this example. You will have to redefine at least two methods:
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_BEGIN
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_PROCESS
By default the changeset_begin method will only allow changeset processing for changesets where the number of requests equals to one. This can be handled automatically that's why a limitation exists. If there were more requests one could not ensure their processing automatically as they could have a business dependency on each other.
So make sure to allow a bundled (deferred mode) processing of changesets under the desired conditions:
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_BEGIN: first call the super->/iwbep/if_mgw_appl_srv_runtime~changeset_begin method in a try catch block, then loop at it_operation_info to decide and narrow down processing only in selected cases and then allow cv_defer_mode only for the selected cases, otherwise throw a /iwbep/cx_mgw_tech_exception=>changeset_not_supported exception.
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_PROCESS: all requests will be available in the it_changeset_request. Make sure to fill the ct_changeset_response table with the responses.
METHOD /iwbep/if_mgw_appl_srv_runtime~changeset_process.
DATA:
lv_operation_counter TYPE i VALUE 0,
lr_context TYPE REF TO /iwbep/cl_mgw_request,
lr_entry_provider TYPE REF TO /iwbep/if_mgw_entry_provider,
lr_message_container TYPE REF TO /iwbep/if_message_container,
lr_entity_data TYPE REF TO data,
ls_context_details TYPE /iwbep/if_mgw_core_srv_runtime=>ty_s_mgw_request_context,
ls_changeset_response LIKE LINE OF ct_changeset_response.
FIELD-SYMBOLS:
<fs_ls_changeset_request> LIKE LINE OF it_changeset_request.
LOOP AT it_changeset_request ASSIGNING <fs_ls_changeset_request>.
lr_context ?= <fs_ls_changeset_request>-request_context.
lr_entry_provider = <fs_ls_changeset_request>-entry_provider.
lr_message_container = <fs_ls_changeset_request>-msg_container.
ls_context_details = lr_context->get_request_details( ).
CASE ls_context_details-target_entity.
WHEN 'SomeEntity'.
"Do the processing here
WHEN OTHERS.
ENDCASE.
ENDLOOP.
ENDMETHOD.
From the error I can tell you must be using SAP GW :-) This happens only for batch requests containing more than one create/delete/update calls and it's related to transaction security ("all or nothing"). What you have to do is redefining the corresponding GW method, I think it was CHANGESET_BEGIN. See https://archive.sap.com/discussions/thread/3562720 for some details (can't offer more for now...).

Jira issue status not getting updated

I am trying to update Jira issue fields through REST Api, I am able to update summary, description, priority, reporter fields but the status.
Here is the code I am trying to run:
string jSonContent = (#"
{
""fields"": {
""summary"": ""data"",
""description"": ""modified."",
""priority"": {""name"": ""val""},
""reporter"": {""name"": ""abcdef#gmail.com""},
""status"": {""name"": ""WORK IN PROGRESS""}
}
}").Replace("data", summ).Replace("modified.", desc).Replace("val", pri);
request.AddParameter("application/json", jSonContent, ParameterType.RequestBody);
var response = Execute(request);
You cannot change the status of an issue the way like that.
To determine what type of fields could be changed with a simple PUT request do a GET for metadata:
https://{your-jira-url}/rest/api/2/issue/{issueIdOrKey}/editmeta
This query in turn will provide you all the fields that you can modify. You won't find status field in the returned JSON object.
Back to your problem: How could be the status of an issue changed? In Jira you have a workflow that holds the possible transition between the states. In order to change the state you need to do a transition. (Exactly the same way as you would do it on UI.)
So first do a GET request like that:
https://{your-jira-url}/rest/api/2/issue/{issueIdOrKey}/transitions?expand=transitions.fields
This request will return all possible transitions of your issue's current state. Check which transition you want to perform and note it's ID (in my case the wished ID is 11). With this transition ID you can do a POST request with the JSON payload:
https://{your-jira-url}/rest/api/2/issue/{issueIdOrKey}/transitions
{
"transition": {
"id": "11"
}
}
One additional thing to note: If your transition isn't a simple one then you have to provide more data. I mean a simple transition here where you simply would click on a button on the UI and you wouldn't get an extra screen for the transition. (E.g. you can setup a transition like: you only could resolve an issue if you add a comment to it.) Fortunately, the previously returned transition list contains all the fields that could or that must be provided together with the transition ID.
You can find more information in official Jira documentation.

MVC Button Click performs action without redirecting

I have a table where users are allowed to "tick" or "cross" out a row. Ticking a row changes the status value to "Approved" and crossing it changes it to "Disapproved". I'm currently using the Edit scaffold to perform it. How do I do this without having the user being redirected to the view. I just want the user to click it and the page refreshes, with the status value being updated.
I'm not sure what code to post here either since I don't know how to write it. If any part of my program is required, please let me know. I'll include it here. Thank you :>
Add css classes to the 2 buttons "approve-btn" and "reject-btn".
Create javascript function to approve and reject and bind them to
the 2 classes
Create 2 backend functions
Make ajax calls from the JS functions to your backend functions passing the id of the row item
In the "success:" of the ajax call manage the change of the status to show "approved" or "rejected"
To make ajax call you can use the following example (although there are tons of example on google). Since you're modifying data you should use POST call and since it is a POST call, you should add a RequestVerificationToken to prevent CSRF attacks.
function Approve(id){
securityToken = $('[name=__RequestVerificationToken]').val();
$.ajax({
url: '/YourControllerName/Approve/' + itemId,
type: 'POST',
data: {
"__RequestVerificationToken": securityToken
},
success: function (data) {
if (data == 'success')
//use jQuery to show the approved message;
else
alert("something went wrong");
},
error: function (request, err) {
alert("something went wrong");
}
});
}
The Token should be created in the View adding this line:
#Html.AntiForgeryToken()

Can you pick a browser target server-side?

I have a form that lets users select checks, and when submitted, creates a PDF, which opens in a new browser tab. It doesn't have any branding, and will probably open in a plugin anyway, so I don't want it taking over my site's tab. So I set the form's target to _blank.
But it's possible for the user to submit the form without enough information to create the PDF, in which case I flag the error (server-side) and re-render the form. But because I set the form's target, this re-render opens in a new tab as well, and that's not what I want - in this case, I want it to behave as if target were _top.
So the question is: Can I change the browser's rendering target server-side?
Yes, I know that this can be done with client-side JavaScript, but JS annoys me, and I have to do the validation server-side anyway. I may end up having to use it, but please don't suggest it as an answer - I'm more curious if what I'm attempting can even be done.
PS: I'm on Ruby on Rails 2.3.8, in case anyone knows a framework-specific solution.
A workaround on this problem would be to use the content-disposition header on the pdf, in order to force the file to be downloaded, and avoid the whole "target" approach..
Content-type: application/pdf
Content-Disposition: attachment; filename="downloaded.pdf"
No. This is a purely client-specific feature. As a matter of fact, it's quite possible to get a browser that supports only one window and where the target attribute would have simply no effect. There were even efforts to make this attribute disappear from future HTML standards completely (for instance, the XHTML branch had no such attribute).
The only overlap that I can think of between HTML and HTTP are the <meta http-equiv> tags (where HTML can affect otherwise HTTP-controlled behavior). HTTP is a transfer protocol, designed to work with about just any kind of data. Letting it control presentation would be a pretty terrible mix of concerns.
Fortunately, we live in a JavaScript-enabled world. It is rather easy to validate a form using an AJAX request, especially with libraries like jQuery.
For instance, this script performs a POST request to an URL (in this case, /pdf/validate) and expects the page to send back "ok" (if everything's good) or something else if there was an error.
<form method="post" action="/pdf/send" id="pdf-form">
<!-- form stuff here -->
</form>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
$(document).ready(function()
{
// set to true if we are to bypass the check
// this will happen once we've confirmed the parameters are okay
var programmaticSubmit = false;
// attach an event handler for when the form is submitted
// this allows us to perform our own checks beforehand; we'll do so by
// cancelling the event the user triggered, and do the submit ourselves if
// we detect no error
$('#pdf-form').submit(function(event)
{
if (!programmaticSubmit)
{
// first off, cancel the event
event.preventDefault();
// do an AJAX request to /pdf/validate
$.ajax("/pdf/validate", {
type: "POST",
data: $(this).serialize(), // send the form data as POST data
success: function(result)
{
// this gets called if the HTTP request did not end
// abnormally (i.e. no 4xx or 5xx status);
// you may also want to specify an "error" function to
// handle such cases
if (result == "ok")
{
// since the server says the data is okay, we trigger
// the event again by ourselves, but bypassing the
// checks this time
programmaticSubmit = true;
$(this).submit();
}
else // something went wrong! somehow display the error
alert(result);
}
});
}
});
});
</script>

Resources