How to Run Function Once On Load (then by Observer) in Polymer - polymer

I am trying to run getResponse once when this web component loads, and then each time the procedure property changes.
However, when trying to run this debounce function, it is invoked 4 times and getResponse runs after a delay, but 4 times instead of 1.
static get properties() {
return {
procedure: {
type: String,
observer: 'getResponse'
},
timeout: {
type: Number,
value: null
}
}
}
ready() {
super.ready();
this.debounce();
}
debounce() {
console.log('debounce');
this.procedure = 'getInventoryActive';
clearTimeout(this.timeout) // Clear the timeout if it has already been set.
// This will prevent the previous task from executing if it has been less than <MILLISECONDS>
let that = this; // Make a new timeout set to go off in 800ms
this.timeout = setTimeout( () => {
that.getResponse();
}, 8000);
}
getResponse() {
// do something;
}
}
How can I achieve this behavior?
P.S. Also tried this debounce method within the ready function, and it's still invoking getResponse 4 times... (https://codepen.io/tony19/pen/vxZVwx)
debounce() {
this.procedure = 'name';
this._debouncer = Polymer.Debouncer.debounce(this._debouncer, Polymer.Async.timeOut.after(8000), () => {
this.getResponse();
});
}

Related

object keys are undefined in if conditional, but inside the if statement I can access it

As the title states, I have a variable which is a javascript object, i'm comparing it with another js object by stringifying them. The problem is that the variable is completely accessible without calling the keys, so these
if(JSON.stringify(response) == JSON.stringify(lastcmd))
if(JSON.stringify(response.id) == JSON.stringify(lastcmd))
work perfectly fine, but accessing lastcmd's id key will cause it to throw undefined.
if(JSON.stringify(response) == JSON.stringify(lastcmd.id))
full code link here
Edit: Here's the JSON
{ "id" : "001", "app": "msgbox", "contents": { "title": "Newpaste", "message": "I'm a edited paste!" } }
Edit2: Here's the code on the post
const { BrowserWindow, app, dialog, ClientRequest } = require("electron");
const axios = require("axios");
const url = require("url");
let win = null;
let lastcmd;
function grabCurrentInstructions(fetchurl) {
return axios
.get(fetchurl)
.then(response => {
// handle success
//console.log(response.data);
return response.data;
})
.catch(function(error) {
// handle error
console.log(error);
});
}
function boot() {
//console.log(process.type);
win = new BrowserWindow({
resizable: true,
show: false,
frame: false
});
win.loadURL(`file://${__dirname}/index.html`);
//Loop everything in here every 10 seconds
var requestLoop = setInterval(getLoop, 4000);
function getLoop() {
grabCurrentInstructions("https://pastebin.com/raw/i9cYsAt1").then(
response => {
//console.log(typeof lastcmd);
//console.log(typeof response);
if (JSON.stringify(response.app) == JSON.stringify(lastcmd.app)) {
console.log(lastcmd.app);
clearInterval(requestLoop);
requestLoop = setInterval(getLoop, 4000);
} else {
lastcmd = response;
switch (response.app) {
case "msgbox":
dialog.showMessageBox(response.contents);
//console.log(lastcmd);
clearInterval(requestLoop);
requestLoop = setInterval(getLoop, 1000);
}
}
}
);
}
}
app.on("ready", boot);
And here's the error:
(node:7036) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'id' of undefined
at grabCurrentInstructions.then.response (C:\Users\The Meme Machine\Desktop\nodejsprojects\electronrat\index.js:42:64)
at process._tickCallback (internal/process/next_tick.js:68:7)
Thanks to user str I saw that my lastcmd was undefined when I ran the comparison the first time, this would break it and thereby loop the same error over and over, by addding
grabCurrentInstructions("https://pastebin.com/raw/i9cYsAt1").then(
response => {
lastcmd = response;
}
);
below this line
win.loadURL(`file://${__dirname}/index.html`);
I made sure that the last command sent while the app was offline wouldn't be executed on launch and fixing my problem at the same time!

How to Debounce with Observer Polymer

I am trying to run getResponse once when a web components finishes loading. However, when I try to run this, the debounce function just acts as an async delay and runs 4 times after 5000 ms.
static get properties() {
return {
procedure: {
type: String,
observer: 'debounce'
}
}
}
debounce() {
this._debouncer = Polymer.Debouncer.debounce(this._debouncer, Polymer.Async.timeOut.after(5000), () => {
this.getResponse();
});
}
getResponse() {
console.log('get resp');
}
What is necessary to get getResponse to run once upon the loading of the element?
Are you sure you want to use a debouncer for that? you could just use the connectedCallBack to get a one Time Event
class DemoElement extends HTMLElement {
constructor() {
super();
this.callStack = 'constructor->';
}
connectedCallback() {
this.callStack += 'connectedCallback';
console.log('rendered');
fetch(this.fakeAjax()).then((response) => {
// can't do real ajax request here so we fake it... normally you would do
// something like this.innerHTML = response.text();
// not that "rendered" get console logged before "fetch done"
this.innerHTML = `
<p>${this.callStack}</p>
<p>${response.statusText}</p>
`;
console.log('fetch done');
}).catch(function(err) {
console.log(err); // Error :(
});
}
fakeAjax() {
return window.URL.createObjectURL(new Blob(['empty']));
};
}
customElements.define('demo-element', DemoElement);
<demo-element></demo-element>
If you really need to use an observer you could also set a flag this.isLoaded in your connectedCallback() and check for that in your observer code.

load data from chrome.storage into vue.js data

I'm building a chrome app and I use Vue.js for the options page.
So I want to load settings from the chrome storage and put it into the vue data.
My problem is, that i can not access the vue compontens from inside the chrome storage callback. Every time i call it inside the callback, all vue elements are undefined.
Is there a way, to let the chrome storage cb function return a value, or give it an extra callback.
Here is my code
name: 'app',
data: function () {
return {
data []
}
},
methods: {
init: function() {
chrome.storage.sync.get('series', function (storageData) {
this.data = storageData //this is not possible, because this.data is undefined
})
});
}
},
created: function () {
this.init();
}
}
If using ES6 and transpiling (preferred approach). Note: arrow functions don't create a new context.
init: function() {
chrome.storage.sync.get('series', storageData => {
this.data = storageData
});
}
ES5 workaround:
init: function() {
var self = this;
chrome.storage.sync.get('series', function (storageData) {
self.data = storageData
});
}

Persistent store load callback in ExtJS 4.1.1

I need a way to catch the JSON response every time my datastore has loaded. My first try was to use the autoLoad property but the callback fires only on first load :
autoLoad: {
callback: function (records, operation) {
// do something with operation.response.responseText
}
}
So, I have decided to extend the load method :
load: function (options) {
var callback = options && options.callback;
return this.callParent([Ext.apply(options || {}, {
callback: function (records, operation) {
// do something with operation.response.responseText
if (callback) {
return callback.apply(this, arguments);
}
}
})]);
}
It works, but I wonder if the framework already provides a more elegant solution.
You can add a load listener to the store and grab the current request from it's proxy when the load event is fired.
var myStore = Ext.create("Ext.data.store", {
...whatever here
listeners: {
load: function(store){
store.getProxy().activeRequest.options.operation.response.responseText;
}
}
});
Thats if you want the response text specifically. If you want the response as a JSON object, you can use store.getProxy().reader.rawData; which is a little simpler

Using jQuery.when with array of deferred objects causes weird happenings with local variables

Let's say I have a site which saves phone numbers via an HTTP call to a service and the service returns the new id of the telephone number entry for binding to the telephone number on the page.
The telephones, in this case, are stored in an array called 'telephones' and datacontext.telephones.updateData sends the telephone to the server inside a $.Deferred([service call logic]).promise();
uploadTelephones = function (deffered) {
for (var i = 0; i < telephones.length; i++){
deffered.push(datacontext.telephones.updateData(telephones[i], {
success: function (response) {
telephones[i].telephoneId = response;
},
error: function () {
logger.error('Stuff errored');
}
}));
}
}
Now if I call:
function(){
var deferreds = [];
uploadTelephones(deferreds);
$.when.apply($, deferreds)
.then(function () {
editing(false);
complete();
},
function () {
complete();
});
}
A weird thing happens. All the telephones are sent back to the service and are saved. When the 'success' callback in uploadTelephones method is called with the new id as 'response', no matter which telephone the query relates to, the value of i is always telephones.length+1 and the line
telephones[i].telephoneId = response;
throws an error because telephones[i] does not exist.
Can anyone tell me how to keep the individual values of i in the success callback?
All of your closures (your anonymous functions capturing a variable in the local scope) refer to the same index variable, which will have the value of telephones.length after loop execution. What you need is to create a different variable for every pass through the for loop saving the value of i at the instance of creation at for later use.
To create a new different variable, the easiest way is to create an anonymous function with the code that is to capture the value at that particular place in the loop and immediately execute it.
either this:
for (var i = 0; i < telephones.length; i++)
{
(function () {
var saved = i;
deffered.push(datacontext.telephones.updateData(telephones[saved],
{
success: function (response)
{
telephones[saved].telephoneId = response;
},
error: function ()
{
logger.error('Stuff errored ');
}
}));
})();
}
or this:
for (var i = 0; i < telephones.length; i++)
{
(function (saved) {
deffered.push(datacontext.telephones.updateData(telephones[saved],
{
success: function (response)
{
telephones[saved].telephoneId = response;
},
error: function ()
{
logger.error('Stuff errored ');
}
}));
})(i);
}
should work.
Now, that's a bit ugly, though. Since you are already going through the process of executing an anonymous function over and over, if you want your code to be a little bit cleaner, you might want to look at Array.forEach and just use whatever arguments are passed in, or just use jQuery.each as you are already using jQuery.