Unflattening line items in inputData when rendered by function - javascript

I have dynamic children input fields that need to be rendered in a function, but when they are, then they are not included in inputData properly/not under the parent input field's key. When the children are included directly in the inputFields, it works as expected, but I can't use a function within the children array with Zapier.
Here is the inputData currently, when the line items are rendered in a function, the LI_ denotes that it is a child input key -
"inputData": {
"supplier": "1",
"LI_budget": 1,
"LI_tax": 1,
"company": "1",
"currency": "1",
"LI_price": "1",
"LI_description": "1"
}
I'm expecting ("parent" is the inputField parent key here):
"inputData": {
"supplier": "1",
"parent": [{
"LI_budget": 1,
"LI_tax": 1,
"LI_price": "1",
"LI_description": "1"
}],
"company": "1",
"currency": "1",
}
This is the function I'm using to pull in the parent and children input fields:
const getLineItems = async (z, bundle) => {
let lineItem = {
key: 'parent',
children: [{
key: 'LI_description',
label: 'Description',
required: true
},
{
key: 'LI_budget',
required: true,
label: 'Budget',
dynamic: 'budget.id'
},
{
key: 'LI_price',
required: true,
type: 'number',
label: 'Unit price',
helpText: 'Example: 50.25'
},
{
key: 'LI_tax',
required: true,
label: 'Tax Rate',
dynamic: 'tax_rate.id'
},
]
}
return [lineItem];
};
There are dynamic fields generated in the getLineItems function that I took out to simplify. TIA

Caleb here from Zapier Platform Support. This is a tough one! We have a pretty long-standing issue report on our platform for supporting custom fields with parent keys (it boils down to a chicken vs the egg problem that really makes my head spin when I read the discussion on the issue). Your inputFields function is spot-on, it's just a matter of properly storing it in the bundle on our part.
I think we could cobble together a workaround to unflatten it. Before I do that though, could you give this a test in the editor and submit actual line items from a previous step to this step? I'm not sure what the inputData looks like (e.g. if multiple items are split like 1,2,3 or in some other fashion). If you want to iterate on this, it might be better to switch over to our public developer Slack (http://zpr.io/ttvdr); then we can post the results here for the next person to run into this. 😁

Related

nested autocomplete with selectize plugin

I am using the query-builder plugin in combination with selectize.js plugin to have autocomplete in my query-builder enabled and it works perfectly.
What I would like to know is whether there is any out of the box way to achieve nested autocomplete with selectize.js, or if not any, which part of code could I customize in the plugin to achieve this functionality.
Example of current autocomplete
Code of current autocomplete
values = [{...}] //values holds the json array of the example
plugin = 'selectize';
input = 'text';
plugin_config = {
valueField: 'value',
labelField: 'value',
searchField: ['value'],
sortField: 'value',
nesting: true,
searchFieldOptions: [{nesting: true}],
create: true,
maxItems: 1,
onInitialize: function() {
var that = this;
values.forEach(function(item) {
that.addOption(item);
});
}
};
valueSetter = function(rule, value) {
rule.$el.find('.rule-value-container input')[0].selectize.setValue(value);
}
JSON example
[{
"value": "AnyRole",
"arrayofobjs": [{
"value": "firstobj"
},
{
"value": "secondobj"
}
]
},
{
"value": "Administrator",
"arrayofobjs": [{
"value": "firstobj"
},
{
"value": "secondobj"
}
]
}]
Considering the json sample above, I would like to search inside arrayofobjs when typing the . notation after an option of object values as shown below.
a
AnyRole
Administrator
Manager
and when selecting f.e 'Administrator' and type the dot notation
Administrator.
firstobj
secondobj
The same way editors do with objects.
Is there anything out of the box? I have searched in the selectize.js examples as well as into other threads on GitHub but did not find anything related to it. In case there is not any, I could make a custom solution myself but it would be great if anyone gives me any tips on which part of code and what should I do, thanks in advance :)

Add fields in DevExpress Pivot using AngularJS

I'm looking at this template to build a web application: https://js.devexpress.com/Demos/WidgetsGallery/Demo/PivotGrid/FieldChooser/AngularJS/Light/
In the example there are static data. I have to retrieve them from the server. So, I wrote this:
$scope.testData = [];
$scope.pivotGridDataSource = new DevExpress.data.PivotGridDataSource({
fields: [{
caption: "Nome",
dataField: "fullName",
area: "row"
}, {
caption: "Country",
dataField: "country",
area: "column"
}, {
caption: "Count",
dataField: "countOne",
dataType: "number",
summaryType: "sum",
area: "data"
}],
store: $scope.testData
});
$scope.pivotGridOptions = {
allowSortingBySummary: true,
allowSorting: true,
allowFiltering: true,
showBorders: true,
dataSource: $scope.pivotGridDataSource,
fieldChooser: {
enabled: false
}
},
$scope.fieldChooserOptions = {
dataSource: $scope.pivotGridDataSource,
texts: {
allFields: "All",
columnFields: "Columns",
dataFields: "Data",
rowFields: "Rows",
filterFields: "Filter"
},
width: 400,
height: 400,
bindingOptions: {
layout: "layout"
}
};
// Now I call the server to retrieve data
$scope.getTestData = () => {
$scope.testData.length = 0;
result.forEach(e => {
$scope.testData.push(e);
);
$scope.pivotGridDataSource.reload();
}
$scope.getTestData();
The problem is that when the data are loaded, in the Fields below it shows just the fields written at the beginning (so the name, the count and the country). But I saw in the demo that it should be display ALL parameters of the object.
For example, if the object is so structured:
{ "name": "Test1", "country": "Germany", "creationDate": "xxx", "surname": "yyy" }
So, I expect that in the fields there should be ALL parameters, so name, country, creationDate, surname. So, I did this at the beginning:
I changed $scope.testData = [] into:
$scope.testData = [{ "name": "", "country": "", "creationDate": "", "surname": "" }]
so the component will preparare all fields. And this works. But what if the server gives me back an Object that has another parameters? How can I display them?
I tried so after the calling and before the reload():
let fields = $scope.pivotGridDataSource.fields();
let newField = {
llowExpandAll: false,
allowFiltering: true,
allowSorting: true,
allowSortingBySummary: true,
caption: "This is a new field",
dataField: "newField",
dataType: "string",
displayFolder: "",
index: fields.length
}
$scope.pivotGridDataSource.fields().push(newField);
$scope.pivotGridDataSource.reload();
But it doesn't work yet. Worse, it does not even initialize the Pivot.
The fieldChooser uses the store fields, in this case $scope.testData fields, in your code I see your store is first declared (as null or with some format as you described) and then you have a function to fill it.
I don't know how your code looks and why you create your store that way, but that is basically your problem (the flow).
In the sample code the flow is:
Store with data (static in this case)
PivotGridDataSource
FieldChooser
In your code the flow is:
Store (empty)
PivotGridDataSource
FieldChooser
Store (fill) --> at this point your FieldChooser has been initialized with the fields of the empty version of your store so not much to do (in Jquery you could re-create your object, you dan do it using Jquery within AngularJs see a simple code sample here and below)
$('#chartContainer').dxChart('instance').dispose();
$('#chartContainer').dxPieChart({
...
});
To avoid all of this you can just use the DevExpress.data.CustomStore and your flow will be basically identical to the demo.

JSON database module for Ruby/Sinatra? A JS lowDB alternative for Ruby/Sinatra?

I have to deal with a huge json like this acting as live datasource, is loaded every 5 min from a url..
sports: [
{
id: 200,
title: "Horse Racing",
meetings: [ ],
is_virtual: false,
events: [...],
pos: 83
},
{
id: 600,
title: "Tennis",
meetings: [ ],
is_virtual: false,
events: [
{
id: 301804310,
is_virtual: false,
outcomes: [
{
id: 32779738900,
description: "Brown/Pliskova",
},
{
id: 32779738900,
description: "Brown/Pliskova",
}]
}]
}]
And need to write methods like
getAllSports() returning an array object with all sports
getSport(sport_id) returning the object with this sport id
getAllEvents(Sport) returning all events list object of this sprot
getEvent(Sport, event_id) returning events that matches with given event_id
getOutcomes(Event, outcomes) ... and so on
Is there is a library that parses the json and already have methods some methods to help me to do this kind of stuff? example: obj.find(sport_id)...
In JS you have LowDB https://github.com/typicode/lowdb for this, any similar in Ruby/Sinatra? Or any approach suggestion? Im not using Rails.
Thanks in advice
You could always use Ruby's built in JSON library. You would be able to do something like
json_string = '{"name": "my name", "age": 5}'
object = JSON.parse(json_string)
object["name"] => "my name"
You can then use regular ruby hash / array functions on the returned object. In your case, you could do something along the lines of
def getSport(json_object, id)
json_object["sports"].select { | h | h["id"] == id }.first
end
Which, assuming you have already parsed the JSON and passed the resulting value into that function, would return the sport that had the given ID.

AngularJS : Guidance to implement a factory, service, directive or something else

I'm very new to angularjs and need some advice about the angular way to implement something very simple. In my $scope I need to set some field defaults, and these defaults are needed multiple times in my controller.
I want to be able to refactor these defaults out to a common place, to thin out the controller and allow for code reuse, but not sure if this should be a factory, directive or service.
Heres an example of the defaults:
$scope.skills = [{
description: '',
years: "1",
level: "0",
years_values: [
{ id: "1", description: "1" },
{ id: "2", description: "2" },
{ id: "3", description: "3+" }],
level_values: [
{ id: "0", description: "Starter"},
{ id: "1", description: "Intermediate"},
{ id: "2", description: "Advanced"} ]
}]
Here's an example of where I'd like to call the "new function":
skillSuccess = (resp)->
Loader.hide();
$rootScope.current_user = resp;
#TODO replace this repetition
$scope.skills = [{
description: '',
.... etc
My questions are:
Should I use a factory/directive/service, (or something else) for
this refactoring?
How do I ensure that the function gets called
initially so that the default values are available for the fields
when the page loads?
Should I use a factory/directive/service, (or something else) for this
refactoring?
I'd suggest you to create a constant because looks like you have defaults data which has initially has some value and that will going to be change by the user from the front-end. So you could place that in angular constant, then that constant will be accessed by the factory/service. And Factory/service will do the needful manipulation from its function. To make available constant in your service/factory you need to inject constant name in your service.
By looking at your current requirement you shouldn't be take consideration of directive component.
Constant
app.constant('defaults', [{
description: '',
years: "1",
level: "0",
years_values: [
{ id: "1", description: "1" },
{ id: "2", description: "2" },
{ id: "3", description: "3+" }],
level_values: [
{ id: "0", description: "Starter"},
{ id: "1", description: "Intermediate"},
{ id: "2", description: "Advanced"} ]
}]);
Service
app.service('dataService', function(defaults){
var dataService = this;
dataService.defaults = defaults;
dataService.defaults = angular.copy(defaults) //will return same copy every-time
dataService.getDefaults = function(){
return dataService.defaults;
}
//other method will lie here
})
How do I ensure that the function gets called initially so that the default values are available for the fields when the page loads?
You could simply get that defaults by consuming getDefaults method of your service, then stored that retrieved defaults and use those for manipulation.
If you want the defaults copy to instantiated every-time then use angular.copy(defaults) which will give you the copy of defaults.
Controller
app.controller('myCtrl', function($scope, dataService){
$scope.defaults = dataService.getDefaults(); //this will have defaults
//...other stuff here...
});
Should I use a factory/directive/service, (or something else) for this refactoring?
A controller should be used to set the scope, but the default values should be stored as a constant and returned by a factory. A factory pattern is preferred here because it is a singleton.
angular.module('myApp')
.factory('skillsFactory', function (defaultSkills) {
var service = {};
service.getDefaults = function () {
return defaultSkills;
};
return service;
})
.constant('defaultSkills', [{
description: '',
years: "1",
level: "0",
years_values: [{
id: "1",
description: "1"
}, {
id: "2",
description: "2"
}, {
id: "3",
description: "3+"
}],
level_values: [{
id: "0",
description: "Starter"
}, {
id: "1",
description: "Intermediate"
}, {
id: "2",
description: "Advanced"
}]
}]);
How do I ensure that the function gets called initially so that the default values are available for the fields when the page loads?
In your controller, call $scope.skills = skillsFactory.getDefaults();
angular.module('myApp')
.controller('skillsCtrl', function ($scope, skillsFactory) {
$scope.skills = skillsFactory.getDefaults();
});

Using an input element to reference a json

bit of background: when a user clicks an element, it loads a form retrieved by an ajax call. I save a copy of the json in the controller, and when they change a value, it is to update the local json.
Let's say the json is something like this:
{
name: "questions!",
id: "0",
questions: [{
id: "1",
text: "ninjas or pirates?",
type: "radio",
answers: [{
id: "1",
text: "ninjas"
} , {
id: "2",
text: "pirates"
}],
}, {
id: "3",
text: "why?",
type: "text"
answers: []
}]
}
the element returned is a jquery-ized version of the input that was selected.
While I could iterate through each field and check, I can't help but feel like there is a better way to do it and reference it more directly. How would this be done?

Categories

Resources