Try to get the cause for an Ajax.post failure (using Scala.Js) but get only the class name:
Ajax.post(
url = "...",
data = "...",
headers = Map("Content-Type"->"application/json; charset=utf-8",
"Csrf-Token" -> "...")
).map(_.responseText).map(
content => content match {
case _ => ...
}
).onFailure {
case err => log.info(s"failure ${err.toString} ${err.getCause} ${err.getMessage}")
}
I get:
failure org.scalajs.dom.ext.AjaxException null null
Is it possible to get the cause?
Thanks
I don't think so. As the AjaxException can not be constructed with a cause:
case class AjaxException(xhr: dom.XMLHttpRequest) extends Exception {
def isTimeout = xhr.status == 0 && xhr.readyState == 4
}
Related
I am new to Angular and i am facing some difficulties with a task. I have an array of IDs that i want to execute the same GET Call over. And for every GET call result i have to do some operations and then add the result of every operation to some arrays. I managed to find a way to do it correctly. But my problem is, i can't manage to wait for the final result to be ready (after all the GET calls are done and the operations too) before giving it as an argument to another method that will send it with a POST call.
the method where i do the GET calls and the operations over every call's result (the problem occurs when i am in the rollBackSPN condition).
async getComponentIds(taskName: String, selectedComponents: IComponent[]) {
const componentsId: number[] = [];
const componentsWithoutParams: IComponent[] = [];
let sendPortaPrecedente : boolean;
if(taskName == "rollBackSPN"){
from(selectedComponents).pipe(
concatMap(component =>{
return this.http.get<any>("Url"+component.idComponent).pipe(
tap(val => {
sendPortaPrecedente = true;
for(const obj of val){
if((obj.name == "z0bpqPrevious" && obj.value == null) || (obj.name == "datePortaPrevious" && obj.value == null) || (obj.name == "typePortaPrevious" && obj.value == null)){
sendPortaPrecedente = false;
}
}
if(sendPortaPrecedente){
componentsId.push(component.idComponent);
}else{
componentsWithoutParams.push(component);
}
}),
catchError(err => {
return of(err);
})
)
})
).subscribe(val => {
return { componentsId : componentsId, componentsWithoutParams : componentsWithoutParams, sendPortaPrecedente : sendPortaPrecedente};
});
}else{
for (const component of selectedComponents) {
componentsId.push(component.idComponent)
return { componentsId : componentsId, componentsWithoutParams : componentsWithoutParams, sendPortaPrecedente : sendPortaPrecedente};
}
}
}
The method where i pass the getComponentIds(taskName: String, selectedComponents: IComponent[]) result so it can be send with a POST call (again when i am in the rollBackSPN condition)
executeTask(serviceIdSi: string, actionIdSi: string, actionClassName: string, componentName: string, taskName: string,
componentsId: number[], componentsWithoutParams: IComponent[], sendPortaPrecedente: boolean): Observable<any> {
const url = this.taskUrl + `?serviceId=${serviceIdSi}` + `&actionId=${actionIdSi}` + `&actionClassName=${actionClassName}`
+ `&componentName=${componentName}` + `&taskName=${taskName}`;
if(taskName == "rollBackSPN"){
if(sendPortaPrecedente && componentsWithoutParams.length == 0){
return this.http.post<any>(url, componentsId);
}else{
let errMessage = "Some Error Message"
for(const component of componentsWithoutParams){
errMessage = errMessage + component.idComponent +"\n";
}
throw throwError(errMessage);
}
}else{
return this.http.post<any>(url, componentsId);
}
}
Both these methods are defined in a service called TaskService.
And the service is called like this in a component UnitTaskButtonsComponent.
async launchUnitTask() {
this.isLoading = true;
this.isClosed = false;
this.appComponent.currentComponentIndex = this.componentIndex;
let res = await this.taskService.getComponentIds(this.unitTaskLabel, this.selectedComponents);
this.taskService.executeTask(this.appComponent.currentService.identifiantSi,
this.appComponent.currentAction.identifiantSi,
this.appComponent.currentAction.className,
this.selectedComponents[0].name,
this.unitTaskLabel,
res.componentsId,
res.componentsWithoutParams,
res.sendPortaPrecedente).subscribe(
data => this.executeTaskSuccess(),
error => this.executeTaskError());
}
"res" properties are always undefined when it's a rollBackSPN task.
The main issue here is that getComponentIds does not return a Promise. So awaiting does not work. I would suggest to change getComponentIds so that it returns an Observable instead.
getComponentIds(taskName: string, selectedComponents: IComponent[]) {
// ^^^^^^ use string instead of String
return forkJoin(
selectedComponents.map((component) => {
return this.http.get<any>("Url" + component.idComponent).pipe(
map((val) => {
let sendPortaPrecedente = true;
for (const obj of val) {
if (
(obj.name == "z0bpqPrevious" && obj.value == null) ||
(obj.name == "datePortaPrevious" && obj.value == null) ||
(obj.name == "typePortaPrevious" && obj.value == null)
) {
sendPortaPrecedente = false;
}
}
return { component, sendPortaPrecedente }
}),
catchError((err) => of(err))
);
})
).pipe(
map((result) => {
const componentsId: number[] = [];
const componentsWithoutParams: IComponent[] = [];
for (const val of result) {
if (val.sendPortaPrecedente) {
componentsId.push(val.component.idComponent);
} else {
componentsWithoutParams.push(val.component);
}
}
return { componentsId, componentsWithoutParams };
})
);
}
Instead of using concatMap, let's use a forkJoin. The forkJoin allows sending all requests in parallel and returns the result in an array. But we have to pass in an array of Observables. That's why we map over the selectedComponents.
In the lower map, we can now get the complete result of the http calls in the result parameter. Here we do the processing of the data. I was not really sure how to handle the sendPortaPrecedente. You will have to fill that in.
We simply return the whole Observable
async launchUnitTask() {
this.taskService
.getComponentIds(this.unitTaskLabel, this.selectedComponents)
.pipe(
switchMap((res) => {
this.taskService
.executeTask(
this.appComponent.currentService.identifiantSi,
this.appComponent.currentAction.identifiantSi,
this.appComponent.currentAction.className,
this.selectedComponents[0].name,
this.unitTaskLabel,
res.componentsId,
res.componentsWithoutParams,
res.sendPortaPrecedente
)
})
).subscribe(
(data) => this.executeTaskSuccess(),
(error) => this.executeTaskError()
);
}
In the launchUnitTask method, we don't use await anymore. Instead, we call getComponentIds and chain the call of executeTask with a switchMap.
I have an aggregation written in a MyRepository.kt file which is being called from MongoDataRetriever.kt file in the backend.
MyRepository.kt file:
import org.springframework.data.mongodb.repository.Aggregation
import org.springframework.data.mongodb.repository.MongoRepository
#Aggregation(pipeline = [
"{ \$match: { 'objName' : { \$exists: true } } }",
"{ \$sort: { 'addedDate': -1 } }"
])
fun getLatestObjectsWithLatestData(): List<MyDocument>
and MongoDataRetriever.kt file:
override fun getLatestObjects(): List<MyObj> {
return myRepository.getLatestObjectsWithLatestData().map { it.toMyObj() }
}
The above aggregation is failing with error:
message: "Command failed with error 16819 (Location16819): 'Sort exceeded memory limit of 104857600 bytes, but did not opt in to external sorting. Aborting operation. Pass allowDiskUse:true to opt in.' on serv...
So, It seems adding allowDiskUse = true or something like that is the possible fix, but how to add that in the above annotation?
You can add #Meta(allowDiskUse = true) annotation to your method.
#Aggregation(pipeline = [
"{ \$match: { 'objName' : { \$exists: true } } }",
"{ \$sort: { 'addedDate': -1 } }"
])
#Meta(allowDiskUse = true)
fun getLatestObjectsWithLatestData(): List<MyDocument>
In redux Promise.resolve(dispatch(null)) is possible?
I am trying to dispatch null in order to create an action ? Will this be possible?
This is not possible in redux. As redux documentation says, an action can only be dispatched when it is a plain object and type of action is not undefined.
Here is the code snippet for dispatch function in redux/src/createStore.js file.
function dispatch(action) {
if (!isPlainObject(action)) {
throw new Error(
'Actions must be plain objects. ' +
'Use custom middleware for async actions.'
)
}
if (typeof action.type === 'undefined') {
throw new Error(
'Actions may not have an undefined "type" property. ' +
'Have you misspelled a constant?'
)
}
if (isDispatching) {
throw new Error('Reducers may not dispatch actions.')
}
try {
isDispatching = true
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
const listeners = currentListeners = nextListeners
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
return action
}
Instead of dispatching like the way you suggested, a better implementation would be
Promise.resolve(dispatch({ type: 'YOUR_SAMPLE_ACTION_TYPE', data: null }))
I hope it helps. Thanks!
I'm getting "TypeError: Cannot read property 'length' of null" when calling sender.set_selectedToggleStateIndex(val) within a nested function that is used as a radprompt callback.
sender is a radbutton (ButtonType = Toggle; ToggleType = CustomToggle).
Although this may not be relevant: the radButton is initiated in a radgrid via Custom GridTemplateColumn.
OnToggleValueChangingResultHandler = function (sender, e, args, result) {
if ((result) ? result.isValid : false) {
return true;
} else {
if (result.StatusCode == 200) {
radprompt(result.message, OnToggleValueChangingPromptCallBackFn, 400, 350, null, result.title || "Prompt - Override", false);
} else {
radalert(result.message || "Internal Error Occurred!", 400, 350, result.title || "Alert - Error", null, null);
}
return false;
}
function OnToggleValueChangingPromptCallBackFn(promptArgs) {
promptArgs = promptArgs || { "override": false, "note": "" };
if (promptArgs.override && promptArgs.note.length > 0) {
args.Override = promptArgs.override;
args.OverrideNote = promptArgs.note;
var result = Paysheet.XHR.POST(args._uri, args);
result.isValid = true;
if ((result) ? result.isValid : false) {
// $find(sender.id).set_selectedToggleStateIndex(args.newIndex);
sender.set_selectedToggleStateIndex(args.newIndex);
} else {
if (result.StatusCode == 200) {
radalert(result.message || "Override request denied!", 400, 350, result.title || "Alert - Override Denied", null, null);
} else {
radalert(result.message || "Internal Error Occurred!", 400, 350, result.title || "Alert - Error", null, null);
}
}
} else {
// ensuring the control retains the same value; for the prompt is async;
}
}
}
This pattern seems to work properly with a radcombobox and a series of radtextboxes. Additionally, the eventArgs seem more robust.
I suspect this issue is rooted in ClientState persistence and referencing: controlStates and/or viewState being lossed.
If I attempt to call sender.get_selectedToggleState() or sender.get_selectedToggleStateIndex() in the PromptCallbackFn, I get an error stating this._functionality is undefined. _functionality seems to be in regards to controlstate.
Note:
sender.get_clientStateFieldID() returns the ClientID properly, but $find(sender.get_clientStateFieldID()) returns null.
sender.get_toggleStateData() returns the data properly. but
sender.get_toggleStates() returns null.
sender.get_parent() returns null.
The answer turned out to be to set the Autopostback = false of the RadButton.
such a minor oversight.
the postback went unnoticed for me because of the nature of these controls.
Part of my UrlMappings looks like this:
"/$lang"(controller: "main", action: "front") {
constraints {
lang inList: ['hr', 'sl', 'si']
}
}
Because I want to set lang to 'sl' if it is 'si', I created following filter:
def filters = {
all(controller: '*', action: '*') {
before = {
if(params.lang == 'si') {
params.lang = 'sl'
}
}
}
}
Problem: params.lang inside controller gets the wanted value ('sl'), but in views, params.lang gets resolved to the original value ('si'). What would you suggest to solve this problem?
Thank you!
Try to use redirects. I did this way:
def filters = {
pages(controller: 'pages', action: 'home|services|projects|project_details|contact_us|career|about_us|downloadCaseStudy') {
before = {
if (params.lang) {
if (!(params.lang in grailsApplication.config.i18nFields.locales)) {
session."$SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME" = null
params.remove('lang')
response.sendError(404)
return
}
if (params.lang == grailsApplication.config.defaultLocale) {
RCU.getLocaleResolver(request).setLocale(request, response, new Locale(params.lang))
params.remove('lang')
chain(controller: "pages", action: params.action, model:chainModel?:[:],params: params)
return false
}
} else {
String langCode = RCU.getLocale(request).getLanguage()
if (!(langCode in grailsApplication.config.i18nFields.locales)) {
params.lang = grailsApplication.config.defaultLocale
return
} else if (langCode != grailsApplication.config.defaultLocale) {
params.lang = langCode
chain(controller: params.controller, action: params.action, model:chainModel?:[:], params: params)
}
return true
}
}
after = { Map model ->
}
afterView = { Exception e ->
}
}
A little explanation: I build urls like /ru/about_us.
1.If lang not in list - 404.
2.if lang = grailsApplication.config.defaultLocale show instead of /en/about_us just /about_us.
3. if no lang param provided - resolve from request.