web service is called several times - javascript

I have a web service which is called 3 times and I don't know why ?
This is the web service WLOLBLOK. I would like to call this web service once time only.
file.service.ts
getInstrumentBlockDetail(portfolioID, svm) {
var payload = {
"HEADER": this.sh.getHeaderForRequest(),
"CUSTOMER": {
"REFERENCE": portfolioID,
"ID": "",
"INTITULE1": "",
"INTITULE2": "",
"ACCESS": 0,
"SERVICE": 0,
"DEFAULTPTF": 0
},
"SVM": svm
}
return this.http.post < any[] > (this.getBaseUrl() + `/WLOLBLOK`, payload);
}
file.ts
ngOnInit() {
this.svm = this.AR.snapshot.paramMap.get('svm');
this.currentPortfolio = this.shrd.getData('currentPortfolio');
this.pageTitle = "";
this.initiate();
}
getBlocked() {
return this.api.getInstrumentBlockDetail(this.currentPortfolio, this.svm)
.pipe(
map((response: {}) => {
this.prepareDataForBlocked(response);
})
);
}
prepareDataForBlocked(res) {
if (res.RETURNCODE == 'OKK00') {
this.spinners.blockDetails = false;
this.pageTitle = " " + res.BLOCAGES.INFOTITRE.LABEL + " (" + res.BLOCAGES.INFOTITRE.PLACELABEL + ")";
}
}
getBlocage() {
return this.api.getInstrumentBlockDetail(this.currentPortfolio, this.svm)
.pipe(
map((response: {}) => {
this.prepareDataForBlocage(response);
})
);
}
prepareDataForBlocage(response) {
this.spinners.blockDetails = false;
if (response['RETURNCODE'] == "OKK00") {
this.myList = response['BLOCAGES']['BLOCAGE']
.filter(blocage => blocage['QTE'] != 0)
.map(blocage => ({
quantity: blocage['QTE'],
raison: blocage['RAISON_LIB'],
update: blocage['DAT'],
rem1: blocage['REM1'],
rem2: blocage['REM2']
}));
let totalQt = response['BLOCAGES']['QTEBLOQTOT'];
this.statusLine = {
total: totalQt
};
}
}
initiate() {
this.getBlocked().subscribe(res => {
this.spinners.blockDetails = true;
this.getBlocage()
.pipe(
concatMap(res => this.getBlocage()),
).subscribe()
})
}
goBack() {
this.helpers.goBack();
}
How can I solve this problem, please ?
Thank you so much.

Use share observable for RxJs operator.

Related

How can i clear the chat input-box after sending the message(from suggestion) in botframework webchat?

i'm working on a bot application using react js and botframework webchat. The thing is that i want to clear the text input box (from where msgs are sent) after sending the message - which is selected from the suggestion. The Suggestion list(or autocomplete component) is a custom coded one. And What i mean is that if i type "hr" the suggestion list popup will come and if i click on one option from the suggestion, say 'hr portal', it will be sent, but what i wrote ie "hr" remains there in the input field and i want to clear that. And please note that If i type something and send its working fine. The problem is only when i type something and select something from the suggestion. Everything else is fine. How can i clear that. Any help would be really appreciated.
please find the below image for more understanding.
here's my code;
import React from 'react';
import { DirectLine, ConnectionStatus } from 'botframework-directlinejs';
import ReactWebChat from 'botframework-webchat';
import './ChatComponent.css';
var val;
var apiParameters = [];
var currentFocus = -1;
export default class extends React.Component {
constructor(props) {
super(props);
this.state = {
token: '',
conversationId: '',
directLine: {},
view: false,
feedBack: null,
value: '',
popupContent: '',
storeValue: '',
suggestions: [],
suggestionCallback: '',
suggestionTypedText: "",
typingChecking: "false",
};
this.handleTokenGeneration = this.handleTokenGeneration.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleSaveFeedback = this.handleSaveFeedback.bind(this);
this.handleSuggestion = this.handleSuggestion.bind(this);
this.handleClose = this.handleClose.bind(this);
this.handleSuggestionClick = this.handleSuggestionClick.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this);
this.moveHighlight = this.moveHighlight.bind(this);
this.getSuggestionHtml = this.getSuggestionHtml.bind(this);
}
getSuggestionHtml(suggestion) {
const lowerCaseSuggestion = suggestion.toLowerCase();
return {
__html: lowerCaseSuggestion.includes(this.state.suggestionTypedText) ? lowerCaseSuggestion
.replace(this.state.suggestionTypedText, `<b>${this.state.suggestionTypedText}</b>`) : lowerCaseSuggestion
};
}
handleTokenGeneration = async () => {
console.log("11111");
const response = await fetch(`api/TokenGenerationService/GetToken`);
const data = await response.json();
this.setState({
token: data.categoryObject.token, conversationId:
data.categoryObject.conversationId
});
this.state.directLine = new DirectLine({ token: this.state.token });
this.setState({ view: true });
this.setState({ typingChecking: "true" });
console.log("conversationId");
};
async handleSuggestion(val, store) {
if (val === "") {
this.setState({
suggestions: []
});
}
else {
apiParameters = [];
var valuess = null;
const response = await fetch(`api/TokenGenerationService/GetAzureSearch?myparam1=${val}`);
const data = await response.json();
var values = ["Hello", "yes", "no", "exit", "Welcome", "Thank You", "Approve", "Apply leave", "Reject", "Absence Balance", "Leave Balance", "Upcoming Holidays", "Apply Comp-Off", "Approve Leave", "Raise Incident Tickets", "Project Allocation Info", "Reporting Manager Change", "Reporting Manager Approval", "Approve Isolve Tickets", "My Manager", "My Account Manager", "Generate Salary Certificate", "Isolve Ticket Status", "Internal Job Posting", "My Designation", "My Joining Date", "RM Approval", "RM Change", "Resource Allocation", "ESettlement Approval", "SO Approval", "Cash advance Approval", "Purchase Request Approval", "Referral status", "HR Ticket", "Platinum Support"];
valuess = values.filter(s =>
s.toLocaleLowerCase().startsWith(val.toLowerCase())
);
valuess = valuess.concat(data.az_search);
this.setState({
suggestions: valuess,
suggestionCallback: store,
suggestionTypedText: val.toLowerCase()
});
// alert(data.az_search);
var totCount = data.az_search;
console.log("kkkkkk" + totCount);
}
}
moveHighlight(event, direction) {
event.preventDefault();
const { highlightedIndex, suggestions } = this.state;
if (!suggestions.length) return;
let newIndex = (highlightedIndex + direction + suggestions.length) % suggestions.length;
if (newIndex !== highlightedIndex) {
this.setState({
highlightedIndex: newIndex,
});
}
}
keyDownHandlers = {
ArrowDown(event) {
this.moveHighlight(event, 1);
},
ArrowUp(event) {
this.moveHighlight(event, -1);
},
Enter(event) {
const { suggestions } = this.state;
if (!suggestions.length) {
// menu is closed so there is no selection to accept -> do nothing
return
}
event.preventDefault()
this.applySuggestion(suggestions[this.state.highlightedIndex]);
},
}
handleKeyDown(event) {
// console.log("lokkkkkkkkkkkk")
if (this.keyDownHandlers[event.key])
this.keyDownHandlers[event.key].call(this, event)
}
async handleSuggestionClick(event) {
await this.applySuggestion(event.currentTarget.textContent);
}
async applySuggestion(newValue) {
//newValue = null;
await this.setState({ typingChecking: "false", suggestions: [], highlightedIndex: 0 });
this.state.suggestionCallback.dispatch({
type: 'WEB_CHAT/SEND_MESSAGE',
payload: {
text: newValue
}
});
await this.setState({ typingChecking: "true" });
}
getSuggestionCss(index) {
var HIGHLIGHTED_CSS = "HIGHLIGHTED_CSS";
var SUGGESTION_CSS = "SUGGESTION_CSS";
return index === this.state.highlightedIndex ? HIGHLIGHTED_CSS : SUGGESTION_CSS;
}
handleClose(elmnt) {
var x = document.getElementsByClassName("autocomplete-items");
for (var i = 0; i < x.length; i++) {
if (elmnt !== x[i]) {
x[i].parentNode.removeChild(x[i]);
}
}
}
async componentDidMount() {
try {
await this.handleTokenGeneration();
const store =
window.WebChat.createStore(
{},
({ getState }) => next => action => {
this.state.directLine.connectionStatus$
.subscribe(connectionStatus => {
if (connectionStatus === ConnectionStatus.ExpiredToken) {
console.log("expired");
}
if (action.type === 'WEB_CHAT/SET_SEND_BOX') {
const val = action.payload.text;
if (this.state.typingChecking === "true") {
this.setState({
highlightedIndex: -1,
});
console.log(this.state.typingChecking);
this.handleSuggestion(val, store);
}
}
if (action.type === 'DIRECT_LINE/DISCONNECT_FULFILLED') {
console.log("final" + connectionStatus);
console.log("finalexpired" + ConnectionStatus.ExpiredToken);
console.log("final");
this.handleTokenGeneration();
}
});
return next(action)
}
);
this.setState({ storeValue: store });
} catch (error) {
console.log("error in fetching token");
console.log(error);
}
this.state.directLine.activity$
.filter(activity => activity.type === 'message')
.subscribe(function (activity) {
//console.log("oooooooooooooooooooooo");
}
// message => console.log("received message ", message.text)
);
}
handleSaveFeedback(ans) {
// console.log(this.state.conversationId);
// console.log(this.state.feedBack);
var userID = "C94570";
var feedbackmsg = this.state.value;
var feedbacktype = this.state.feedBack;
var convId = this.state.conversationId;
fetch('api/Feedback/SaveFeedback',
{
method: "POST",
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ Uid: userID, FeedbackMessage: feedbackmsg, Convid: convId, FeedbackType: feedbacktype })
}).
then(response => response.text())
.then(data => {
console.log(data.getResult);
});
this.setState({ value: '' });
}
feedback(ans) {
this.setState({ feedBack: ans });
if (ans === "Send") {
this.handleSaveFeedback(ans);
}
else if (ans === "Yes") {
this.setState({ popupContent: "How was your experience?" });
// console.log(this.state.value)
}
else if (ans === "No") {
this.setState({ popupContent: "What went wrong?" });
// console.log(this.state.value)
}
}
handleChange = (event) => {
this.setState({ value: event.target.value });
}
styleOptions = {
bubbleBackground: 'rgba(0, 0, 255, .1)',
bubbleFromUserBackground: 'rgba(0, 255, 0, .1)',
botAvatarInitials: 'DIA',
userAvatarInitials: 'ME'
}
render() {
if (!this.state.view) {
return
<div />
} else {
const filteredSuggestions = this.state.suggestions.filter(
suggestion =>
suggestion.toLowerCase().indexOf(this.state.suggestionTypedText.toLowerCase())
> -1
);
// console.log(this.state.view);
return (
<div className="react-container webchat" >
<div onKeyDown={this.handleKeyDown.bind(this)}>
<div >
<ReactWebChat styleOptions={this.styleOptions} directLine={this.state.directLine} webSocket={true} userID='C94570' username='Thomas' store={this.state.storeValue} sendTypingIndicator={true} />
</div>
</div>
<div className="SuggestionParent" id="Suggestion1">
{this.state.suggestions.map((suggestion, index) => (
<div className={this.getSuggestionCss(index)} key={index} onClick={this.handleSuggestionClick} >
{suggestion
.toLowerCase()
.startsWith(this.state.suggestionTypedText) ? (
<div>
<b>{this.state.suggestionTypedText}</b>
{suggestion
.toLowerCase()
.replace(this.state.suggestionTypedText, "")}
</div>
) : (
<div dangerouslySetInnerHTML={this.getSuggestionHtml(suggestion)} />
)}
</div>
))}
</div>
<footer className="chat-footer" >
<div className="foot-footer">
Was I helpful ?
<span className="feedback" onClick={() => this.feedback("Yes")} >Yes</span><span>|</span><span className="feedback" onClick={() => this.feedback("No")}>No</span>
{
this.state.feedBack === "Yes" || this.state.feedBack === "No" ?
(
<div className="dialog" id="myform">
<div id="textfeedback">
<span id="closeFeedback" onClick={() => this.feedback("Close")}>X</span>
<p>{this.state.popupContent}</p>
<input type="text" id="feedbacktxtbox" required name="textfeedback" placeholder="Pleasure to hear from u!"
onChange={this.handleChange}
value={this.state.value} />
<button type="button" id="btnfeedback" onClick={() => this.feedback("Send")}>send</button>
</div>
</div>
) : null
}
</div>
</footer>
</div>
);
}
}
}
The chat input box is called the send box in Web Chat. Clearing the send box is just setting the send box with an empty string. This is done automatically when you click on the send button normally. You can see in the submit send box saga that submitting the send box means performing two actions: sending the message and setting the send box.
if (sendBoxValue) {
yield put(sendMessage(sendBoxValue.trim(), method, { channelData }));
yield put(setSendBox(''));
}
This means that if you use the SUBMIT_SEND_BOX action then the send box will be cleared automatically. Of course, if you want that to work with your autocomplete component then you'll need to set the send box with the autocompleted text before you submit it. Your other option is to just use the SET_SEND_BOX action with an empty string after you send the message.

RxJs BehaviorSubject for Array that allow setting/subscribing to individual items

I would like to use a BehaviorSubject to store an Array of objects and have a way to easily update (next?) a single item of that array without having to update the whole array.
I would also like for an easy way to subscribe to changes to an specific item of that array. I know it could be done with filter, but an easier way would be nice...
Is that possible?
I am currently using this version I created (which I don't know if it is the best way or not) that also persists its contents to localstorage:
export class LocalStorageBehaviorSubject<T, Y = T> {
private _data: BehaviorSubject<T>;
public asObservable() {
return this._data.asObservable();
}
public next(data: T) {
if(this.expirationFn !== null) {
data = this.expirationFn(data);
}
localStorage.setItem(this.key, JSON.stringify(data));
this._data.next(data);
}
public nextItem(item: Y) {
if (!Array.isArray(this._data.getValue())) {
throw "Type is not an Array";
}
let dados: any = (<any>this._data.getValue()).slice();
if (dados.some(r => r[this.id] === item[this.id])) {
dados = dados.map(r => r[this.id] === item[this.id] ? item : r);
} else {
dados.push(item);
}
if(this.expirationFn !== null) {
dados = this.expirationFn(dados);
}
localStorage.setItem(this.key, JSON.stringify(dados));
this._data.next(<any>dados);
}
public removeItem(id) {
if (!Array.isArray(this._data.getValue())) {
throw "Type is not an Array";
}
let dados: any = (<any>this._data.getValue()).slice();
dados = dados.filter(r => r[this.id] !== id);
localStorage.setItem(this.key, JSON.stringify(dados));
this._data.next(<any>dados);
}
public removeExpiredData(){
let data = this.loadFromStorage();
if (data) {
if(this.expirationFn !== null) {
data = this.expirationFn(data);
}
this._data.next(data);
}
}
public getValue() {
this.removeExpiredData();
return this._data.getValue();
}
public getItem(id): Y {
if (!Array.isArray(this._data.getValue())) {
throw "Type is not an Array";
}
this.removeExpiredData();
return (<any>this._data.getValue()).slice().find(t => t[this.id] == id);
}
constructor(private key: string, private id: string, defaultValue: any = null, private expirationFn: (dados: T) => T = null) {
this._data = new BehaviorSubject<T>(defaultValue);
this.removeExpiredData();
}
private loadFromStorage(): T {
let dadosStr = localStorage.getItem(this.key);
if (dadosStr) {
return JSON.parse(dadosStr);
}
return null;
}
}
I hoped that would be an simpler way...
Thanks
I would also like for an easy way to subscribe to changes to an
specific item of that array. I know it could be done with filter, but
an easier way would be nice...
You can use map operator and inside lambda array.find
Example
const mockStorage = {
values: {},
setItem(key, value) {
this.values[key] = value;
},
getItem(key) {
return this.values[key]
},
clearItem(key) {
this.values[key] = undefined;
}
}
class LocalStorageBehaviorSubject {
constructor(key, defaultValue) {
this.key = key;
this._data = new rxjs.BehaviorSubject(defaultValue);
}
nextItem(item) {
const list = this._data.value;
const itemIndex = list.findIndex(pr => pr.id === item.id);
this._data.next([
...list.slice(0, itemIndex),
{
...(list[itemIndex] || {}),
...item
},
...list.slice(itemIndex + 1)
]);
}
removeItem(id) {
this._data.next(this._data.value.filter(pr => pr.id !== id));
}
getItem(id) {
return this.asObservable()
.pipe(
rxjs.operators.map(values => values.find(pr => pr.id === id) || null),
rxjs.operators.distinctUntilChanged());
}
asObservable() {
return this._data.asObservable().pipe(
rxjs.operators.tap(values => {
if (values && values.length) {
mockStorage.setItem(this.key, JSON.stringify(values));
}
else {
mockStorage.clearItem(this.key);
}
}))
}
}
const localStorageBehaviorSubject = new LocalStorageBehaviorSubject('items', []);
localStorageBehaviorSubject
.getItem(1)
.subscribe(item => {
console.log(item);
})
localStorageBehaviorSubject.nextItem({id: 1, value: 'test'})
localStorageBehaviorSubject.nextItem({id: 1, value: 'test1'})
localStorageBehaviorSubject.nextItem({id: 2, value: 'test2'})
localStorageBehaviorSubject.nextItem({id: 3, value: 'test3'})
localStorageBehaviorSubject.removeItem(2);
localStorageBehaviorSubject.removeItem(1);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.js"></script>

How to add a value into an object which is inside map function?

I am using map function to iterate an object. but in one scenario i have to use nested map function. I try to add an value to an empty object inside an map function, but instead of adding values it replacing it. can anyone help me with this?
// object stores final results
let valid_data={}
//object to iterate
let test_cases = {
sample:
[ { test_case_no: 1,
test_case_description: 'user-status active - response 200',
value: 'active',
response_code: 200,
valid: 'yes' },
{ test_case_no: 2,
test_case_description: 'user-status inactive - response 200',
value: 'inactive',
response_code: 200,
valid: 'no' },
{ test_case_no: 3,
test_case_description: ' inappropriate user-status - response 400',
value: 'notAdmin',
response_code: 400,
valid: 'no' } ],
sample1: [ { obj1: [Array], obj2: [Array], test_case_no: 4 } ]
}
//my code to iterate an object
Object.entries(test_cases).map((property) => {
const field_name = property[0]
const field_definition = property[1]
Object.entries(field_definition).map((property) => {
if (property[1].valid != 'yes' && property[1].valid != 'no') {
Object.entries(field_definition).map((property) => {
Object.entries(property[1]).map((propertyy) => {
Object.entries(propertyy[1]).map((property) => {
nested_data = []
nested_value = {}
if (property[1].valid == 'yes') {
nested_value[propertyy[0]] = property[1].value
nested_data.push(Object.assign({}, nested_value))
valid_data[field_name] = (Object.assign({}, nested_value))
}
})
})
})
}
else if (property[1].valid == 'yes') {
valid_data[field_name] = property[1].value;
}
})
})
console.log(valid_data);
Actual result:
“{ sample: 'active',
sample1: { obj2: 2019-07-01T09:50:46.266Z } }”
Expected result:
“{ sample: 'active',
sample1: [{ obj1: 2019-07-01T09:50:46.266Z,obj2: 2019-07-01T09:50:46.266Z }] }”
Wrong var initialisation in your code.
Try this loop :
Object.entries(test_cases).map((property) => {
const field_name = property[0]
const field_definition = property[1]
Object.entries(field_definition).map((property) => {
if (property[1].valid != 'yes' && property[1].valid != 'no') {
nested_value = {}
Object.entries(property[1]).map((propertyy) => {
Object.entries(propertyy[1]).map((property) => {
if (property[1].valid == 'yes') {
nested_value[propertyy[0]] = property[1].value;
valid_data[field_name] = (Object.assign({},
nested_value))
}
})
})
} else if (property[1].valid == 'yes') {
valid_data[field_name] = property[1].value;
}
})
});
Working jsfiddle
Object.entries(test_cases).map((property) => {
const field_name = property[0]
const field_definition = property[1]
Object.entries(field_definition).map((property) => {
if (property[1].valid != 'yes' && property[1].valid != 'no') {
nested_data = []
nested_value = {}
Object.entries(property[1]).map((propertyy) => {
Object.entries(propertyy[1]).map((property) => {
if (property[1].valid == 'yes') {
nested_value[propertyy[0]] = property[1].value;
if(!nested_data.includes(nested_value)){
nested_data.push(nested_value)
valid_data[field_name] = nested_data
}
}
})
})
} else if (property[1].valid == 'yes') {
valid_data[field_name] = property[1].value;
}
})
})

how can i change row color in react

export class EstimateForm extends React.Component<IEstimateFormProps,
IEstimateFormState> {
state: IEstimateFormState = {
cellUpdateCss: 'red',
toRow: null,
fromRow: null,
estimateList: null,
estimateItemList: [],
poseList: null,
levelList: null,
partList: null,
selectedEstimate: null,
totalEstimateItems: 0,
selectedIndexes: [],
totalEstimateAmount: 0,
grid: null,
projectId: 0,
};
constructor(props, context) {
super(props, context);
this.state.estimateList = this.props.estimateList;
}
rowGetter = i => {
const row = this.state.estimateItemList[i];
const selectRevison = this.state.selectedEstimate.revision;
if (row['pose.poseName']) {
const poseCode = row['pose.poseName'].substring(row['pose.poseName'].lastIndexOf('[') + 1, row['pose.poseName'].lastIndexOf(']'));
for (const pose of this.state.poseList) {
if (pose.poseCode === poseCode) {
row.pose = pose;
}
}
}
if (row['level.levelName']) {
const levelCode = row['level.levelName'].substring(
row['level.levelName'].lastIndexOf('[') + 1,
row['level.levelName'].lastIndexOf(']')
);
for (const level of this.state.levelList) {
if (level.levelCode === levelCode) {
row.level = level;
}
}
}
if (row['level.part.partName']) {
const partCode = row['level.part.partName'].substring(
row['level.part.partName'].lastIndexOf('[') + 1,
row['level.part.partName'].lastIndexOf(']')
);
for (const part of this.state.partList) {
if (part.partCode === partCode) {
row.part = part;
}
}
}
row.get = key => eval('row.' + key);
row.totalCost = (row.materialCost + row.laborCost) * row.amount;
if (row.revision > selectRevison) {
for (let i = 0; i < row.length; i++) {
row[i].style.color = 'red'; // here color is nor change
}
return row;
} else {
return row;
}
}
handleGridRowsUpdated = ({ fromRow, toRow, updated }) => {
const rows = this.state.estimateItemList.slice();
for (let i = fromRow; i <= toRow; i++) {
const rowToUpdate = rows[i];
const updatedRow = update(rowToUpdate, { $merge: updated });
rows[i] = updatedRow;
}
this.setState({ estimateItemList: rows, fromRow: (fromRow), toRow: (toRow)
}, () => {
});
};
saveEstimateItems = () => {
if (this.state.selectedEstimate == null) {
toast.warn(<Translate
contentKey="bpmApp.estimateForm.pleaseSelectEstimate">Please select an
estimate</Translate>);
return;
}
render() {
return ()
}
I wanna to change the row color when the condition row.revision > this.state.selectedEstimate.revision . How can I prevent the change of this.color. However im not get any error but row color is not change. how can i solve this problem it is my first project in react and i dont know where is the problemThanks for your feedback guys.

Fail while replicating data from PouchDb to CouchDb

My Code
thats is a short version of my current code.:
['tableA', 'tableB', 'tableC'].forEach(name => {
let local = new PouchDB(name, { auto_compaction: true })
let server = new PouchDB(serverUrl + name)
var filtro = {
include_docs: true,
filter: 'replication/by_dispositivo',
query_params: { 'dispositivo_id': obj.deviceId }
}
local.replicate.from(server, filtro).on('complete', report => {
var sync = local.sync(server, {
live: true,
retry: true,
...filtro
})
})
})
I'm trying to do a live replication, but for some reason, that doesn't replicate the local data to the server, strangely, PouchDb didn't throw any exception.
Inspecting the Network tab on Dev Tools, I can see te follow request.:
URL: ${serverUrl}/{name}/_revs_diff
Response: {
"4b0ea507-cd88-4998-baf0-01629b50516b": {
"missing": [
"2-2133d30de8d44ebd958cee2b68726ffb"
],
"possible_ancestors": [
"1-39904a7e55b1cb266c840a2acf34fdc2"
]
}
}
Ok, PouchDb detected that something is missing in the server and must be replicated.
Auditing the Sync
Searching for a hint about what is happening, I modified my code to log the complete and error events.:
['tableA', 'tableB', 'tableC'].forEach(name => {
let local = new PouchDB(name, { auto_compaction: true })
let server = new PouchDB(serverUrl + name)
let filtro = {
include_docs: true,
filter: 'replication/by_dispositivo',
query_params: { 'dispositivo_id': obj.deviceId }
}
local.replicate.from(server, filtro).on('complete', report => {
let sync = local.sync(server, {
live: true,
retry: true,
...filtro
})
sync.on('error', (error) => {
console.error(error)
console.error(JSON.stringify(error, null, 2))
}).on('complete', (result) => {
console.log(result)
console.log(JSON.stringify(result, null, 2))
})
window.setTimeout(function (evt) {
state.syncProcess[database].cancel()
}, 15000)
})
})
I didn't catch anything in the error event, and the complete event didn't show any errors as you can see bellow.
{
"push": {
"ok": true,
"start_time": "2018-04-06T15:00:42.266Z",
"docs_read": 0,
"docs_written": 0,
"doc_write_failures": 0,
"errors": [],
"status": "cancelled",
"end_time": "2018-04-06T15:00:42.266Z",
"last_seq": 0
},
"pull": {
"ok": true,
"start_time": "2018-04-06T15:00:26.422Z",
"docs_read": 0,
"docs_written": 0,
"doc_write_failures": 0,
"errors": [],
"last_seq": "17-g1AAAAJDeJyd0EsOgjAQBuAqJj52nkCPILGldCU3UaYzBA3CQl3rTfQmehO9CRZKAiaGiJtpMs18mX8SxtgodpBNdXbSMUKQZDpM4uxwTMxXP2Qwy_N8Fzsh25vGMILIA62QjU8pUrRNCVvGYW4qrCphUgoCfMVd_W2mTQoKaV1JjpWWIUcuu0qbQjp_pBKeUESLH1OlA1PZxTwGudb7EC1dQt5xH6vdrHYvtF6pSZK-4Oov7WG1Z53QUy56UnRK-LJK406-TxIAm8ruDdzts44",
"status": "cancelled",
"end_time": "2018-04-06T15:00:41.427Z"
}
}
Calling one time local to server replication manually
that is my second attempt to catch something usefull. I trying to audit the local.replicate.to method
['tableA', 'tableB', 'tableC'].forEach(name => {
let local = new PouchDB(name, { auto_compaction: true })
let server = new PouchDB(serverUrl + name)
let filtro = {
include_docs: true,
filter: 'replication/by_dispositivo',
query_params: { 'dispositivo_id': obj.deviceId }
}
local.replicate.from(server, filtro).on('complete', report => {
local.replicate.to(server, filtro).on('complete', report => {
console.log(report)
console.log(JSON.stringify(report, null, 2))
let sync = local.sync(server, {
live: true,
retry: true,
...filtro
})
}).on('error', (error) => {
console.error(error)
console.error(JSON.stringify(error, null, 2))
})
})
})
thats time complete event isn't fired and I catch a error, but that is too generic amd don't give any clues regarding whats is happening.
{
"result": {
"ok": false,
"start_time": "2018-04-06T15:07:19.105Z",
"docs_read": 1,
"docs_written": 0,
"doc_write_failures": 0,
"errors": [],
"status": "aborting",
"end_time": "2018-04-06T15:07:19.768Z",
"last_seq": 3
}
}
Putting local data to the server
thats is my last attempt.:
I'll query local and remote databases (in that particular case, I have only one document)
Copy fields from local doc to remote doc.
Dispatch the updated remote doc to the remote database
My Junk Code
var deviceId = ''
var listLocal = []
var listServer = []
getDeviceId().then(response => {
deviceId = response
return local.find({ selector: { dispositivo_id: deviceId } })
}).then(response => {
listLocal = response.docs
return server.find({ selector: { dispositivo_id: deviceId } })
}).then(response => {
listServer = response.docs
var tlocal = listLocal[0]
var tServer = listServer[0]
Object.keys(tServer).forEach(key => {
if (key.indexOf("_") !== 0) {
tServer[key] = undefined
}
})
Object.keys(tlocal).forEach(key => {
if (key.indexOf("_") !== 0) {
tServer[key] = tlocal[key]
}
})
return server.put(tServer).then(result => {
console.log(result)
console.log(JSON.stringify(result, null, 2))
}).catch(error => {
console.error(error)
console.error(JSON.stringify(error, null, 2))
})
})
The junk code worked as expected, and i received that response.:
{
"ok": true,
"id": "4b0ea507-cd88-4998-baf0-01629b50516b",
"rev": "2-d9363f28e53fdc145610f5ad3f75a043"
}
Additional Information
My design documents in the CouchDb
_design/replication
{
"_id": "_design/replication",
"_rev": "1-42df919aaee8ed3fb309bbda999ba03d",
"language": "javascript",
"filters": {
"by_dispositivo": "function(doc, req) {\r\n return doc._id === '_design/replication' || (doc.dispositivo_id === req.query.dispositivo_id && !doc._deleted)\r\n}",
"by_situacao_remote": "function(doc, req) {\r\n return [2, 3, 4, 5].indexOf(doc.situacao) !== -1 && !doc._deleted\r\n}"
}
}
_design/authorization
{
"_id": "_design/authorization",
"_rev": "9-64c4a22645d783c9089c95d69e9424ad",
"language": "javascript",
"validate_doc_update": "..."
}
authorization/validate_doc_update
function(newDoc, oldDoc, userCtx) {
var isAdmin = userCtx.roles.indexOf('_admin') !== -1 || userCtx.roles.indexOf('admin') !== -1;
if (!isAdmin) {
if (newDoc._deleted) {
if (oldDoc.dispositivo_id !== userCtx.name) {
throw({forbidden: "..." });
}
}
else {
if (!newDoc.dispositivo_id || !newDoc.dispositivo_id.trim())
throw({forbidden: "..." });
if (newDoc.dispositivo_id !== userCtx.name) {
throw({forbidden: "..." });
}
if (oldDoc && oldDoc.dispositivo_id !== userCtx.name) {
throw({forbidden: "..." });
}
var isRequired = function (prop, msg) {
var value = newDoc[prop];
if (!value)
throw({forbidden: '...' });
}
var isDate = function (prop, msg, allow_null) {
if (!allow_null)
isRequired(prop, msg)
var value = newDoc[prop];
if (value) {
var date = new Date(value);
var isDate = date !== "Invalid Date" && !isNaN(date);
if (!isDate) {
throw({forbidden: msg });
}
}
}
var isFloat = function (prop, msg, allow_null) {
if (!allow_null)
isRequired(prop, msg)
var value = newDoc[prop];
if (value) {
var numero = new Number(value);
if (!numero || isNaN(numero) || !isFinite(numero)) {
throw({forbidden: msg });
}
}
}
var isInteger = function (prop, msg, allow_null) {
isFloat(prop, msg, allow_null)
var value = newDoc[prop];
if (value) {
var numero = new Number(value);
var isInteger = Math.floor(numero) == numero;
if (!isInteger) {
throw({forbidden: msg });
}
}
}
isRequired("talao_id", "...");
isRequired("equipe_id", "...");
isInteger("situacao", '...');
isDate("data_envio", "...");
isDate("data_recebimento", "...", true);
isDate("data_decisao", "...", true);
isRequired("tipo_ocorrencia_codigo", "...");
isRequired("tipo_ocorrencia_descricao", "...");
isInteger("talao_codigo", "...");
isRequired("talao_descricao", "...");
isRequired("talao_solicitante", "...");
isRequired("talao_endereco", "...");
}
}
else if (!newDoc._deleted) {
if (!newDoc.dispositivo_id || !newDoc.dispositivo_id.trim())
throw({forbidden: "..." });
}
}
While analyzing the stack trace of the exception throw by local.replicate.to, I noticied that reason: promise.all is not a function.
So i googled for a while and found that topic Webpack: Promise is not a constructor. I just need to copy the workaround bellow to my webpack.config and everything worked like a charm.:
resolve: {
alias: {
'pouchdb-promise$': "pouchdb-promise/lib/index.js"
}
}

Categories

Resources