Extra trigger output caused by sample data - zapier

I've used Zapier CLI to create a trigger and it was working great (trigger output looked great, no unwanted fields present). When I submitted the integration to Zapier, they required each trigger to include the sample property:
perform: perform,
performList: performList,
sample: {
data: {
items: [
{
item: {
id: '42c21e82-0772-4d79-a6b3-c916e51b24ff'
},
language: {
id: '00000000-0000-0000-0000-000000000000'
}
}
]
},
//etc..
Since adding this, the trigger's output contains duplicated entries- one populated and one empty:
I'm not sure how to get rid of this.. any ideas? Note: This occurs in triggers where I am and am not using outputFields.

I found the cause- the data in sample was slightly different from the data output by performList.

Related

Is there alternative available to jqx render capability - $gridContainer.jqxGrid('render')

We are using jqxGrid library from jqwidgets. In this I am using jqxDropDownList for displaying list created from json data and upon selecting a value from dropdown filtering should happen.
We had some UI issues hence we had to remove below line, now I would like to know is there alternative available for below code :
code :
$gridContainer.jqxGrid('render')
if you want to update two-way data then you should used observableArray()
here check the demo code jqx observable array
var observableArray = new $.jqx.observableArray(
[{name: "Andrew Smith"},
{name: "Gordon Brown"}],
function(changes)
{
// handle changes here.
});

Create Remote Select2 v4 Option with custom parameters

here is the problem, I can create the custom option as specify on documentation like this:
var option = new Option("my custom option", "myid", true, true);
$('select[name="myselect"]').append(option).trigger('change');
// manually trigger the `select2:select` event
$('select[name="myselect"]').trigger({
type: 'select2:select',
params: {
data: {
id: "myid",
text: "my custom option",
customparam: {
hello: "I'm here"
}
}
}
});
So, this creates the option normally and shows on select2 as selected as expected, this also trigger the select2:select event and I can read the extra parameter when this event is trigger, but here comes the problem, I can NOT access the extra parameter by doing this:
$('select[name="myselect"]').select2('data')[0].customparam
it's like the custom parameter is not attached to the element and it was only pass to the events.
for all who try to find an solution to add the custom parameters back on remote select2, here is what I did and worked perfectly:
$('select[name="yourfieldname"]')
.append(new Option(`${doc.n}`, doc._id, true, true))
.select2('data')[0].customparam = doc.i;
then just when you need call:
$('select[name="yourfieldname"]').select2('data')[0].customparam
The method described by #rafaelrglima's works for me, but I prefer the method below, which was gleaned from dejan9393's answer in Github issue 2830:
var dataAdapter = $('select[name="myselect"]').data('select2').dataAdapter;
dataAdapter.addOptions(dataAdapter.convertToOptions([{
id: "myid",
text: "mycustomoption",
customparam: "hello"
}]));
I prefer this way because I don't have to have one step for adding "id" and "text" and separate step for adding custom parameters. Also convertToOptions takes an array, so you have a convenient way to add multiple options in one step.

Angular reactive forms - How to set default value of select/dropdown control?

This week, i ran into a problem where dropdown control of angular material was not populating the default value coming from the API. My datasource looked like this:
public selectDataSource = [{
id: 1,
name: 'Option 1'
}, {
id: 2,
name: 'Option 2'
}, {
id: 3,
name: 'Option 3'
}];
Value was coming from the API as:
{
'selectedOption': {
id: 2,
name: 'Option 2'
}
}
But somehow, when i assigned the value to reactive form control field, it didn't get auto populated, which ideally should be the expected behavior.
Reason, answer below.... Go on
After all the research, I came to conclusion that Angular will only make a value as default selected if it points to the same memory location as in the original dataSource array.
In the example above, selectDataSource is stored in different memory location whereas the value coming from the API is pointing to different memory location.
Solution: Loop through the original datasource and filter the matched entry with result from API, to get the selected object from the original dataSource and that's it you are done. Something like below:
selectedOption = selectedDataSource.filter((option) => option.id === selectedOption.id)[0];
Now, we have selectedOption pointing to the same memory location from the original dataSource array.
Below is the link to solution. Try toggeling the variable solveProblem to see the default behaviour(when pointing to different memory loctaion).
https://stackblitz.com/edit/angular-reactive-dropdown-control
In a Hope, it'll help someone someday.
Thanks,
Manish Kumar
I had the same problem with dropdowns not showing already saved / selected choices and this answer to another question finally helped.
The solution is using the [compareWith]="compareFunction" property on the select tag to override the default comparison happening. By referencing a custom compare function you can tailor how the matching of initial value to dropdown values should work.
My current solution:
<mat-form-field>
<mat-select formControlName="gender" [compareWith]="compareSelectValues">
<mat-option *ngFor="let gender of genderValues" value="{{gender.id}}">{{gender.label}}</mat-option>
</mat-select>
</mat-form-field>
And Typescript function:
private compareSelectValues(selectedValue, compareValue): boolean {
return Number(selectedValue) === compareValue;
}
Number() is needed as the value is converted to a string after setting it in HTML. Using material design components here but looking at the other post, this shouldn't change the general functionality. Hope this helps someone, who finds this question before the other one, like I did.

Firefox WebExtention won't load

So, I tried to load my add-on using the about:debugging page in Firefox. But, it simply wouldn't load. Is there somewhere where an error would be logged that I could find it?
Here is my manifest.JSON code:
{
"description": "Adds a stickfigure",
"manifest_version": 2,
"name": "StickMan",
"version": "1.0",
"icons": {
"48": "icons/StickMan-48.png"
},
"applications": {
"gecko": {
"id": "extention#stick.man",
"strict_min_version": "45.0"
}
},
"permissions": [
"activeTab"
],
"background": {
"scripts": ["StickManUpdate.js"]
},
"browser_action": {
"default_icon": {
"48": "icons/StickManButton.png"
},
"default_title": "Call StickMan",
},
}
I hope that this helps other frustrated add-on creators.
Thanks in advance
The lack of loading issue is that you have multiple syntax errors in the JSON of your manifest.json file. In your manifest.json file the lines at the end of the file:
"default_title": "Call StickMan",
},
}
Should not have the extra , (which would indicate you are going to have another property in the Object):
"default_title": "Call StickMan"
}
}
If you were using the Firefox Developer Edition, the fact that you had these errors would have been obvious:
However, even if you are running Firefox 47.0.1 and had merely used the Browser Console (keyboard shortcut: Ctrl-Shift-J), as suggested in the comments, you would have seen the error:
A promise chain failed to handle a rejection. Did you forget to '.catch', or did you forget to 'return'?
See https://developer.mozilla.org/Mozilla/JavaScript_code_modules/Promise.jsm/Promise
Date: Sun Jul 17 2016 11:11:22 GMT-0700 (Pacific Standard Time)
Full Message: SyntaxError: JSON.parse: expected double-quoted property name at line 33 column 2 of the JSON data
Full Stack: readJSON/</<#resource://gre/modules/Extension.jsm:628:19
NetUtil_asyncFetch/<.onStopRequest#resource://gre/modules/NetUtil.jsm:128:17
While a bit cryptic, it still shows the line number of the first issue:
Full Message: SyntaxError: JSON.parse: expected double-quoted property name at line 33 column 2 of the JSON data
The error produced in the Browser Console of Firefox Developer Edition is a bit easier to parse as to what the issue is:
SyntaxError: JSON.parse: expected double-quoted property name at line 33 column 2 of the JSON data
Stack trace:
readJSON/</<#resource://gre/modules/Extension.jsm:859:19
NetUtil_asyncFetch/<.onStopRequest#resource://gre/modules/NetUtil.jsm:128:17
WebExtensions Development:
The WebExtensions API is currently in development. If you are developing a WebExtension, you should be using either Firefox Nightly, or Firefox Developer Edition in order to test your code.
More on your code:
Syntax error:
In addition to the above syntax errors, you have more issues. I did not attempt to resolve all of them, but did get sucked into fixing enough so that the add-on was functional. The next reported error, a syntax error, is in your StickManUpdate.js file on the code:
browser.tabs.sendMessage(
message: "End";
);
You have multiple issues here. Please see the tabs.sendMessage() documentation. You are missing the required tabId parameter. In addition, you appear to be mixing-up the difference between having an Object being passed as a parameter containing properties which are the information passed to the method versus a list of parameters which are other native types passed to a method. Note: It is not uncommon for there to be both a list of parameters of various native or non-native types and an Object containing properties which are data passed to the method.
Assuming browserAction is defined:
You use methods of browserAction in multiple locations where it should be browser.browserAction. browserAction by itself is not defined. Alternately, you could use browserAction as a shortcut by defining it like: var browserAction = browser.browserAction;.
Use of browserAction.getTitle() as if it is synchronous when in reality it is asynchronous:
You make a call to browserAction.getTitle() to get the value of the title. The value of the title is only available in the callback function, which you do not supply. This implies a lack of understanding of asynchronous programming. You might want to review some questions on that subject like:
Why isn't a global variable set immediately after defining a callback/listener function (asynchronous messaging, port.on)
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
How do I return the response from an asynchronous call?
Wrong parameter type supplied to browserAction.setTitle():
This appears to, again, be confusion as to the difference between parameters of other native types and a parameter that is an Object (which may be an Object literal) which contains properties which are the information passed to the method. Admittedly, WebExtensions appear to almost arbitrarily mix using actual parameters and Objects with the properties functioning as parameters when passing information to methods. It appears that being careful as to which is being used in a particular method will be required.
Not having various functions specify the ID for the tab:
In multiple calls to various methods, you do not pass the tabId when you should. You are adding your StickMan canvas to a single tab per mouse click. You should be passing the tab ID for calls to multiple methods.
Assigning to document.body.innerHTML in stickman.js:
In general, assigning to innerHTML at any time should be avoided, if possible. It is a bad idea under most circumstances. In most instances, it may cause the entire DOM to be re-evaluated. For doing what you desire, adding HTML in text format to the DOM at the end of the HTML for an element, there is a specific function which is better/faster: insertAdjacentHTML(). Your code:
document.body.innerHTML+= '<canvas id="StickManCanvas0000000" width="100" height="200"></canvas>';
Could be written as:
document.body.insertAdjacentHTML("beforeend", '<canvas id="StickManCanvas0000000" width="100" height="200"></canvas>');
However, it is still a bad idea to use insertAdjacentHTML() here. There is a significant stigma attached to using either insertAdjacentHTML() or assigning to innerHTML. Using either will result in your add-on receiving additional scrutiny when submitted to AMO for distribution. This is mostly because there are real security issues with using either methodology for changing the DOM. The security issues are when what is being added is text that is dynamically generated from input/data which is not hard coded into your add-on. In addition, you are already mixing adding the element as text and performing changes to it using other JavaScript (e.g. assigning to canvas.style.position). You really should use one or the other. In this case, it is better to construct canvas entirely in JavaScript. It is, after all, only 4 lines to do the same thing you were doing in the two you were using for the innerHTML assignment and the getElementById() to find the canvas element.
Personally, I like using insertAdjacentHTML() in many instances with complex structures. It is generally faster to use it for inserting larget amounts of HTML. It also allows you to keep what is being inserted represented as text. Such text may be much easier to visualize the structure being added rather than figuring out what a large chunk of DOM generated using document.createElement() and setAttribute() actually looks like. However, along with the other drawbacks mentioned above, using insertAdjacentHTML() may not lend itself as easily to writing modular code.
Issues with how you insert you content script and canvas:
Every time the user clicks on your browserAction button you insert another copy of your content script into the tab. This leads to issues of errors being generated due to the consumed content scripts getting the message sent by your call to browser.tabs.sendMessage() and not being able to find the canvas. The correct solution to this is to only chrome.tabs.executeScript() the first time the button is clicked in a tab and then send a message to the content script each subsequent time the button is clicked in that tab causing the same canvas to be re-inserted into the DOM. An easy way to track if you have already loaded the StickMan into a particular tab is to use setTitle() to have the title for your button be different after the first run in that tab.
Other issues:
Note: Your code structure in stickman.js is a bit convoluted. You might want to address this.
All together
manifest.json:
{
"description": "Adds a stickfigure",
"manifest_version": 2,
"name": "StickMan",
"version": "1.0",
"icons": {
"48": "icons/StickMan-48.png"
},
"applications": {
"gecko": {
"id": "extention#stick.man",
"strict_min_version": "45.0"
}
},
"permissions": [
"activeTab"
],
"background": {
"scripts": ["StickManUpdate.js"]
},
"browser_action": {
"default_icon": {
"48": "icons/StickManButton.png"
},
"default_title": "Call StickMan",
"browser_style": true
}
}
StickManUpdate.js:
browser.browserAction.onClicked.addListener(function(tab) {
browser.browserAction.getTitle({tabId:tab.id},function(title){
if(title === 'Call StickMan') {
chrome.tabs.executeScript(tab.id, {
file: "/content_scripts/stickman.js"
});
browser.browserAction.setTitle({title:'Recall StickMan',tabId:tab.id});
} else if (title === 'Call StickMan again') {
browser.tabs.sendMessage(tab.id,"Draw");
browser.browserAction.setTitle({title:'Recall StickMan',tabId:tab.id});
}else {
browser.tabs.sendMessage(tab.id,"End");
browser.browserAction.setTitle({title:'Call StickMan again',tabId:tab.id});
}
});
});
stickman.js:
var running = true;
//document.body.insertAdjacentHTML("beforeend", '<canvas id="StickManCanvas0000000" width="100" height="200"></canvas>');
var canvas = document.createElement("canvas");
canvas.setAttribute("width",100);
canvas.setAttribute("height",200);
//var canvas = document.getElementById('StickManCanvas0000000');
canvas.style.position = 'fixed';
canvas.style.left = '0px';
canvas.style.top = (window.innerHeight-200)+'px';
canvas.style.backgroundColor = 'rgba(0, 0, 0, 0)';
canvas.style.border = '1px dashed red';
var ctx = canvas.getContext('2d');
var pos = {
x:0,
headX:50,
headY:20,
bodyX:50,
bodyY:150,
leftArmX:25,
leftArmY:90,
rightArmX:75,
rightArmY:90,
leftLegX:30,
leftLegY:200,
rightLegX:70,
rightLegY:200,
};
var setPos = function(x, y) {
canvas.style.left = x+'px';
canvas.style.top = (window.innerHeight-y-200)+'px';
};
var drawMan = function(time) {
setPos(pos.x, 0);
ctx.strokeStyle = '#000000';
ctx.lineWidth = 5;
ctx.beginPath();
ctx.arc(pos.headX, pos.headY, 20, 0, Math.PI*2, false);
ctx.moveTo(pos.headX, pos.headY);
ctx.lineTo(pos.bodyX, pos.bodyY);
ctx.lineTo(pos.rightLegX, pos.rightLegY);
ctx.moveTo(pos.bodyX, pos.bodyY);
ctx.lineTo(pos.leftLegX, pos.leftLegY);
ctx.moveTo((pos.bodyX+pos.headX)/2, ((pos.bodyY+pos.headY)/5)*2);
ctx.lineTo(pos.rightArmX, pos.rightArmY);
ctx.moveTo((pos.bodyX+pos.headX)/2, ((pos.bodyY+pos.headY)/5)*2);
ctx.lineTo(pos.leftArmX, pos.leftArmY);
ctx.stroke();
ctx.fillStyle = '#888888';
ctx.beginPath();
ctx.arc(pos.headX, pos.headY, 20, 0, Math.PI*2, false);
ctx.fill();
if(running) {
window.requestAnimationFrame(drawMan);
}
};
drawMan();
document.body.appendChild(canvas);
browser.runtime.onMessage.addListener(function(m) {
if(m === 'End' && running === true) {
running = false;
document.body.removeChild(canvas);
} else if(m === 'Draw' && running === false) {
running = true;
document.body.appendChild(canvas);
}
});
Functionality demo [Note1: You must navigate to an actual webpage. Note2: The tooltips that pop up to tell you what the title is of your browser_action button are not captured with the program I used to create the following .gif. Note3: I added the browser_style property to the browser_action in your manifest.json file. It is new in Firefox 48. Without it, Firefox will issue a warning in the Browser Console when the add-on is loaded.]:

Joining Firebase tables in React

I am hoping to display a list of user's notes from a Firebase DB inside of a React app.
After reading through the Firebase recommended approach on structuring data, I've created my database in the flattened format they recommend. The data structure looks something like this:
notes
- [noteKey]
- note: [noteData]
- created_at: [date]
- updated_at: [date]
...
users
- [userKey]
- name: [userName]
- notes
- [noteKey]: true
...
...
Each user has an array called notes, which lists the noteKeys of the notes that they own.
So far I've been able to get the full list of notes (from all users, not what I want), and the user's list of noteKeys. The issue that I'm having is combining those two. I have seen the question about joining tables, but I have more of a React focused question:
In which React function does the join happen?
Right now my code looks like this:
getInitialState: function(){
return {
notesList: []
};
},
componentWillMount: function() {
base = Rebase.createClass('https://appName.firebaseio.com');
base.syncState('notes', {
context: this,
state: 'notesList',
asArray: true,
queries: {
limitToLast: 20
}
});
this.state.notesList.map(function(item, i) {
base.child("notes/" + item['.key'] + "/note").on('child_added', function(snapshot) {
console.log(item['.key'])
});
});
},
I see two issues with this.
When the this.state.notesList.map function is called in componentWillMount, the array hasn't been populated with the Firebase data yet, so it looks like an empty array and returns an error.
Once I solve #1, I'm not sure how to get the user specific notes into it's own array that's accessible by the rest of the component.
--
In which React timeline function should the join be happening?
How do the second table items (the user's notes) get added to an array that is accessible by the rest of the component?
You're working with an async library (re-base) here but you've written synchronous code.
What this means is base.syncState is going to fire off a request to your Firebase instance and in the meantime, your JavaScript is going to just keep happily executing down the line with or without results. It follows that this.state.notesList.map is going to map over an empty array since JS is going to execute faster than a round trip to the server.
Looking at the options available for the syncState method, there's one called then that executes a callback.
then: (function - optional) The callback function that will be invoked when the initial listener is established with Firbase. Typically used (with syncState) to change this.state.loading to false.
This makes me think that it fires after you get your data from Firebase.
Try running your .map in there since you'll actually have the data you want.
componentWillMount: function() {
base = Rebase.createClass('https://appName.firebaseio.com');
base.syncState('notes', {
context: this,
state: 'notesList',
asArray: true,
queries: {
limitToLast: 20
},
then: function() {
this.state.notesList.map(function(item, i) {
base.child("notes/" + item['.key'] + "/note").on('child_added', function(snapshot) {
console.log(item['.key'])
});
});
}
});
}

Resources