I want to load blocks data dynamically to my EditorJS instance.
I would like to do something like this:
const editor = new EditorJS();
editor.load({ blocks: my_blocks })
I do not seem to find any documentation on how to do it on https://editorjs.io/
I know that I can load blocks to EditorJS during initialization, but I need to load dynamic data on button click.
You could use the Blocks Core API, by means of the insert() method, using the below signature:
insert(type?: string, data?: BlockToolData, config?: ToolConfig, index?: number, needToFocus?: boolean): void
So, in your case, it could be:
editor.blocks.insert('header', {text: 'My header'});
Where header is the type and the second argument is the block data
A cleaner approach would be to pre-define your block as follows:
const blockToAdd = {
type: 'header',
data: {
text: 'My header'
}
};
editor.blocks.insert(blockToAdd);
Not sure when this was added to the API, but there is also editor.render(data) which loads JSON data into the editor dynamically.
render(data: OutputData): Promise
Method removes all Blocks and fills with new passed JSON data
Source: https://editorjs.io/blocks#render
Related
I have a component on which I have to add two ReactPixel.track('abc') and
ReactPixel.track('cba'), how can I achieve this? Do I need to add just one ReactPixe.init('id') or two? Here is a code example:
componentDidMount() {
const options = {
autoConfig: false,
};
ReactPixel.init('123123', options);
ReactPixel.pageView();
ReactPixel.track('abc');
ReactPixel.track('cba');
}
You don't need to add multiple React inits on every page.
Just add it on your App.js(If you use create-react-app).
* You should initiate before you use it.
ReactPixel.init('123123', options);
If you need to get pageview details of whole app you need to use the below code.function in entry level.(I prefer after the init function)
ReactPixel.pageView();
There is no magic. It just call the same function that Facebook has given to you. fbq('track', 'PageView');
You can use track codes inside your functions. As a example after registration is successful you can create this track code.
ReactPixel.track('abc',{#data object goes here});
This is the example that Facebook has given.
fbq('track', 'Purchase',
// begin parameter object data
{
value: 115.00,
currency: 'USD',
contents: [
{
id: '301',
quantity: 1,
item_price: 85.00
},
{
id: '401',
quantity: 2,
item_price: 15.00
}],
content_type: 'product'
}
// end parameter object data
);
You can use this same function with react-facebook-pixel wrapper like this.
ReactPixel.track('abc',{#data object goes here});
Tracking Custom Events
You can track custom events by calling the pixel's fbq('trackCustom') function, with your custom event name and (optionally) a JSON object as its parameters. Just like standard events, you can call the fbq('trackCustom') function anywhere between your webpage's opening and closing tags, either when your page loads, or when a visitor performs an action like clicking a button.
For example, let's say you wanted to track visitors who share a promotion in order to get a discount. You could track them using a custom event like this:
fbq('trackCustom', 'ShareDiscount', {promotion: 'share_discount_10%'});
you can track custom events with react wrapper like this
ReactPixel.trackCustom(#title_of_event,#data_object);
If you need more understanding of what this react-facebook-pixel has done. You can read the code of the package.
https://github.com/zsajjad/react-facebook-pixel/blob/master/src/index.js
Facebook documentation: https://developers.facebook.com/docs/facebook-pixel/implementation/conversion-tracking#advanced_match
I'm a little stuck on how to define a conditional type for typescript based on a predefined string literal
This is a mockup / example to help explain For a little background, a user is supposed to label data from images, currently there are only 2 types of things to label (for this example lets say its pedestrians and vehicles) potentially more in the future.
In my Redux store I am storing data from an API request (request gets a new set of data to label based on one of these types). The issue is the data that i get is in different formats for the two types of things to label aka array of frames or object with values that are frame arrays.
type ILabelingTypes = "pedestrians" | "vehicles"
A frame would look like this
interface IFrame {
url: string
orientation: number
// anything else related to a frame
}
The api requests would be /labeling/vehicles/new with an example response
{
// meta info about the labeling session
frames: IFrame[]
}
or /labeling/pedestrians/new with an example response
{
// meta info about the labeling session
frames: Map<string, IFrame[]>
}
The issue I'm having now is when I define my store interface, how do i correctly type the frames key so that I don't have to check everywhere i go to use it what type of data it is?
interface ILabelingStore {
labelingType: ILabelingTypes
frames: // what do i put here?
}
Meaning when i go to render or use this data I'd like to simply call methods that i know exist depending on the labelingType defined in the store
For the React component side, when i go to render the frames I build a queue of frames to complete, so i need to know what type the data is in the respective component (This is what i would like to do instead of having to check the type of frames)
// pedestrians component
componentDidMount() {
Object.entries(this.props.frames).forEach( (key, val) => this.queue.concat(val))
}
// vehicles component
componentDidMount() {
this.queue.concat(this.props.frames)
}
You can create a discriminated union:
type ILabelingStore = ({
labelingType: "vehicles",
frames: IFrame[]
} | {
labelingType: "pedestrians",
frames: { [key: string]: IFrame[] }
});
Demo
The example i'm goint o use here is taken from http://autoform.meteor.com/quickform
I've been using autoform for a few projects, but i need to get this same behaviour without it, how could i do an insert of an Array of objects??
So here is the Schema definition you need with autoform
items: {
type: Array,
optional: true,
minCount: 0,
maxCount: 5
},
"items.$": {
type: Object
},
"items.$.name": {
type: String
},
"items.$.quantity": {
type: Number
}
Next is the call to autoform to generete the form in the template
{{> quickForm id="demo" schema=schemaFromJSON type="method" meteormethod="demoSubmission"}}
With that in place you get a form, displaying both fields: name and quantity, plus a sign for ading more objects with those same fields, and when you actually submit the form it inserts all of your objects.
The HTML and CSS is not the problem
I'm not quite sure what you are asking. These are two ways of inserting arrays to collection:
// insert items one by one
// NOTE: Meteor doesn't allow inserting of arrays like `Items.insert(items)`
items.forEach(item => Items.insert(item));
// insert all items simultaneously by using raw mongo collection:
Items.rawCollection().insert(items);
Kendo Grid is new to me, so I apologize for the ignorance. I'm writing an angular app that uses a separate service to update a local array. It is store in $scope.searchResults variable. I've initialized the grid using the dataSource ->transport property in the hopes that when the array mentioned above is updated, so too will the datasource and the grid updated accordingly. This is not the case. The array is updated, without any problems, but the datasource is never updated. I'll do my best to paste all the code snippets, and console output below.
Html:
<div class="margin-top-25" ng-show="searchResults">
<div id="report-grid" kendo-grid="grid" options="mainGridOptions"></div>
</div>
DataSource proper of the Grid configuration:
dataSource: {
transport: {
read: function read(options) {
options.success($scope.searchResults);
}
},
schema: {
model: {
id: "id",
fields: {
name: {type: "string"},
dataSource: {type: "string"}
}
}
},
pageSize: 10
}
Function for updating the datasource:
function runSearch() {
RetrieveReportsService.query({name: vm.searchData.name, dataSource: vm.searchData.dataSource},
function success(result) {
$log.log($scope.grid.dataSource);
$log.log($scope.searchResults);
$scope.searchResults = result.elements;
$log.log($scope.searchResults);
$scope.grid.dataSource.read();
$log.log($scope.grid.dataSource);
});
}
Now console output:
First time logging the data source:
O…e.e…d.init {options: Object, _map: Object, _prefetch: Object, _data: ObservableArray.extend.init[2], _pristineData: Array[2]…}
First time logging $scope.searchResults:
[Object, Object]
Second time logging $scope.searchResults:
[Object]
Second time logging the data source:
O…e.e…d.init {options: Object, _map: Object, _prefetch: Object, _data: ObservableArray.extend.init[2], _pristineData: Array[2]…}
Note that each data source has an observable array length of 2, before and after the $scope.searchResults has been updated.
I can drill down into the output if it is needed, but didn't want this post to get overwhelming.
Thanks!
Because you are referencing your data that is declared inside your options object by pointing k–options at your options object when the grid initially binds to the options object it's not populated with the data yet. If you reference your data source object separately using k-data-source it will bind to your data source and update your grid when the data source changes. If you want to make changes to your options object trigger a rerender you need to use k–rebind or alternatively the setOptions method. Be sure to read the docs for the latter as there are some caveats.
Well, I don't know why it is working the way that it is, but with the current project configuration this is the solution.
The grid configuration and the function for updating the data source are in the same module. The grid itself is initialized in another controller. I had move the function for updating to the controller that contained the grid and now it works perfectly.
If anyone knows why, feel free to chime in.
For example, say I have a server API for loading people that handles requests like this: GET /people/?id=101,329,27
I'd like to build a Store (probably a custom class that extends Ext.data.Store) which--assuming it has a list of people IDs--causes the proxy to make a request like the one shown above so that the returned data is only for that subset of persons.
I saw the documentation regarding remote filtering, but my concern is that to use it I would first need to call store.load() which would load all persons, then call filter() to do remote filtering. I'd like to just load the subset of persons the first time.
Thanks for any advice!
Found a solution (although still open to hearing other ideas).
First, you can call a store's load() function with a config object that will be passed to an operation. The API docs for Ext.data.Operation make it clear that one of the config options is for an array of Filter objects, so you can do this:
var idFilter = Ext.create('Ext.util.Filter', {
property: 'id',
value: '100,200,300'
});
myStore.load({
filters: [ idFilter ]
});
This results in a request where the URL querystring contains ?filter=[{"property"%3Aid%2C"value"%3A100,200,300}] (in other words, a URL-encoded version of [{ property: 'id', value: '100,200,300'}]).
You can also just call myStore.filter('id', '100,200,300') without having called .load() first. Assuming you have remoteFilter=true in your store, this will make a request with the same query params shown agove.
Sidenote: you can change the keyword used for 'filter' by configuring the 'filterParam' config option for the proxy. For example, if filterParam=q, then the querystring shown above changes to: ?q=[{"property"%3Aid%2C"value"%3A100,200,300}]
Second, you can control "structure" of the filter in the querystring. In my case, I didn't want something like filter={JSON}, as shown above. I wanted a querystring that looked like this:?id=100,200,300
For this I needed to extend a proxy and override the default getParams() function:
Ext.define('myapp.MyRestProxy', {
extend: 'Ext.data.proxy.Rest',
/**
* Override the default getParams() function inherited from Ext.data.proxy.Server.
*
* Note that the object returned by this function will eventually be used by
* Ext.data.Connection.setOptions() to include these parameters via URL
* querystring (if the request is GET) or via HTTP POST body. In either case,
* the object will be converted into one, big, URL-encoded querystring in
* Ext.data.Connection.setOptions() by a call to Ext.Object.toQueryString.
*
* #param {Ext.data.Operation} operation
* #return {Object}
* where keys are request parameter names mapped to values
*/
getParams: function(operation) {
// First call our parent's getParams() function to get a default array
// of parameters (for more info see http://bit.ly/vq4OOl).
var paramsArr = this.callParent(arguments),
paramName,
length;
// If the operation has filters, we'll customize the params array before
// returning it.
if( operation.filters ) {
// Delete whatever filter param the parent getParams() function made
// so that it won't show up in the request querystring.
delete paramsArr[this.filterParam];
// Iterate over array of Ext.util.Filter instances and add each
// filter name/value pair to the array of request params.
for (var i = 0; i < operation.filters.length; i++) {
queryParamName = operation.filters[i].property;
// If one of the query parameter names (from the filter) conflicts
// with an existing parameter name set by the default getParams()
// function, throw an error; this is unacceptable and could cause
// problems that would be hard to debug, otherwise.
if( paramsArr[ queryParamName ] ) {
throw new Error('The operation already has a parameter named "'+paramName+'"');
}
paramsArr[ queryParamName ] = operation.filters[i].value;
}
}
return paramsArr;
}
});
You can also get your Model object to load a record of itself. From a controller you can do:
this.getRequestModel().load(requestID,{ //load from server (async)
success: function(record, operation) {
.....
}
}
where Request is a model class and requestID is an ID to look up. In this scenario Model object needs to define the proxy too:
proxy: {
type: 'ajax',
reader: {
type:'json',
root: 'data'
},
api: {
create : 'request/create.json', //does not persist
read : 'request/show.json'
}
}