I have tried basic packages but I don't seem to get whats going on,
Here is something that I tried;
const {
convertFromHTML,
ContentState
} = require('draft-js');
const htmlToDraft = require('html-to-draftjs');
const converter = () => {
const sampleMarkup =
'<b>Bold text</b>, <i>Italic text</i><br/ ><br />' +
'Example link';
const blocksFromHTML = convertFromHTML(sampleMarkup);
const state = ContentState.createFromBlockArray(blocksFromHTML);
console.log('state: ', state);
}
converter();
It was really clear on which library to use.
I am getting weird looking outputs, what I expect looks something like this;
{
"blocks": [
{
"depth": 0,
"inlineStyleRanges": [
{
"length": 9,
"style": "BOLD",
"offset": 0
},
{
"length": 12,
"style": "ITALIC",
"offset": 11
}
],
"entityRanges": [
{
"length": 12,
"key": 0,
"offset": 25
}
],
"data": {},
"text": "Bold text, Italics text\n\nexample link ",
"key": "9jc4q",
"type": "unstyled"
}
],
"entityMap": {
"0": {
"type": "LINK",
"mutability": "MUTABLE",
"data": {
"url": "http://www.google.com",
"targetOption": "_blank"
}
}
}
}
Any insights ? (code in server side )
const sampleMarkup =
'<b>Bold text</b>, <i>Italic text</i><br/ ><br />' +
'Example link';
const blocksFromHTML = convertFromHTML(sampleMarkup);
const state = ContentState.createFromBlockArray(
blocksFromHTML.contentBlocks,
blocksFromHTML.entityMap,
);
this.state = {
editorState: EditorState.createWithContent(state),
};
Please use this function. 100% working
import htmlToDraft from 'html-to-draftjs';
import { ContentState, EditorState } from 'draft-js';
const htmlToDraftBlocks = (html) => {
const blocksFromHtml = htmlToDraft(html);
const { contentBlocks, entityMap } = blocksFromHtml;
const contentState = ContentState.createFromBlockArray(contentBlocks, entityMap);
const editorState = EditorState.createWithContent(contentState);
return editorState;
}
useEffect(()=>{
setEditorState(htmlToDraftBlocks("<p>Hello</p>"));
},[])
Related
I am using draftjs in which users can type in anything and can also click a button on which I am inserting a IMMUTABLE entity.
const text = "foo";
const editorState = this.state.value;
const selectionState = editorState.getSelection();
const contentState = editorState.getCurrentContent();
const contentStateWithEntity = contentState.createEntity("TOKEN", "IMMUTABLE", { time: new Date().getTime() });
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
const modifiedContent = Modifier.insertText(contentState, selectionState, text, OrderedSet([ "INSERT" ]), entityKey);
const nextState = EditorState.push( editorState, modifiedContent, editorState.getLastChangeType() );
this.setState({value: nextState}, this.focus );
https://codepen.io/dakridge/pen/XgLWJQ
All this is working fine but when the editor state is saved and now I am trying to render the HTML from the saved ContentState in my webpage then I am not able to identify the immutable entity and apply styles to it or render it differently.
For ex, in the above example how can foo be rendered with a different color and how the saved timestamp say can be logged in the console when I hover over foo?
I am using draftjs-to-html to render html from draftjs output.
If you want to track the timestamp (and other data of immutability) then your best option is to store the "raw" form instead of html (or keep alongside the html). You can use the convertToRaw to get the raw content, here's an example of foo inserted with timestamp as epoch.
{
"entityMap": {
"0": {
"type": "TOKEN",
"mutability": "SEGMENTED",
"data": {
"time": 1657116932641
}
}
},
"blocks": [
{
"key": "ekpc6",
"text": "aaa",
"type": "unstyled",
"depth": 0,
"inlineStyleRanges": [],
"entityRanges": [],
"data": {}
},
{
"key": "dmkkr",
"text": "foo",
"type": "unstyled",
"depth": 0,
"inlineStyleRanges": [
{
"offset": 0,
"length": 3,
"style": "INSERT"
}
],
"entityRanges": [
{
"offset": 0,
"length": 3,
"key": 0
}
],
"data": {}
}
]
};
I've taken your codepen code & added an explicit button to get raw content. Once you get the raw JSON, you can extract any meta data out.
const { Editor, EditorState, Modifier, convertToRaw, convertFromRaw } = Draft;
const { OrderedSet } = Immutable;
const sample_saved_state = {
"entityMap": {
"0": {
"type": "TOKEN",
"mutability": "SEGMENTED",
"data": {
"time": 1657116932641
}
}
},
"blocks": [
{
"key": "ekpc6",
"text": "aaa",
"type": "unstyled",
"depth": 0,
"inlineStyleRanges": [],
"entityRanges": [],
"data": {}
},
{
"key": "dmkkr",
"text": "foo",
"type": "unstyled",
"depth": 0,
"inlineStyleRanges": [
{
"offset": 0,
"length": 3,
"style": "INSERT"
}
],
"entityRanges": [
{
"offset": 0,
"length": 3,
"key": 0
}
],
"data": {}
}
]
};
class EditorComponent extends React.Component {
constructor(props) {
super(props);
// In case you store the sample_saved_state as string in server side, you might have to do JSON.parse
console.log("Converting from saved state");
const saved_state = sample_saved_state != null ? EditorState.createWithContent(convertFromRaw(sample_saved_state))
: EditorState.createEmpty();
console.log("Assining to state ");
this.state = {
value : saved_state
};
this.saveContent = this.saveContent.bind(this);
//this.state = { value: EditorState.createEmpty() };
this.onChange = (value) => this.setState({value});
this.focus = () => this.refs.editor.focus();
this.insert = this.insert.bind( this );
}
insert () {
const text = "foo";
const editorState = this.state.value;
const selectionState = editorState.getSelection();
const contentState = editorState.getCurrentContent();
const contentStateWithEntity = contentState.createEntity("TOKEN", "SEGMENTED", { time: new Date().getTime() });
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
const modifiedContent = Modifier.insertText(contentState, selectionState, text, OrderedSet([ "INSERT" ]), entityKey);
const nextState = EditorState.push( editorState, modifiedContent, editorState.getLastChangeType() );
this.setState({value: nextState}, this.focus );
}
saveContent () {
console.log("inside saveContent");
const content = convertToRaw(this.state.value.getCurrentContent());
// you can save the content as json in server side
console.log("Raw Content: ",content)
}
render () {
return (
<div>
<div onClick={ this.focus } className="editor">
<Editor
ref="editor"
onChange={ this.onChange }
editorState={ this.state.value }
customStyleMap={{ "INSERT": { backgroundColor: "yellow", padding: "0 2px" } }}
/>
</div>
<button onClick={ this.insert }>Insert</button>
<button onClick={this.saveContent}>Save</button>
</div>
);
}
}
ReactDOM.render(
<EditorComponent />,
document.getElementById('app')
);
Solution codesandbox: https://codesandbox.io/s/staging-fire-wo3oc5?file=/src/Editor.js
Instead of draftjs-to-html, I recommend draft-convert that comes with the functionality you want. You can customize the output HTML based on style and entity.
const html = convertToHTML({
styleToHTML: (style) => {
if (style === 'INSERT') {
return <span style={{ backgroundColor: 'yellow', padding: '0 2px' }} />;
}
},
entityToHTML: (entity) => {
if (entity.type === 'TOKEN') {
return <span data-time={entity.data.time} className="entity-token" />;
}
},
})(this.state.value.getCurrentContent());
For instance, I am wrapping nodes with the INSERT style inside a styling span, and nodes that correspond with the entity type TOKEN inside a functional span. This will result in an HTML node that looks like this:
Of course, you can combine these logic to wrap your token nodes inside 1 span only, if you want.
The reason we need functional spans is because handling interactions (like displaying time in console on hover) needs custom JavaScript, and we need to do this the old fashioned way. Where you render the HTML, just add the following effect hook:
useEffect(() => {
const tokens = [
...containerRef.current.getElementsByClassName("entity-token")
];
const handler = (event) => {
const timestamp = event.target.dataset.time;
console.log(timestamp);
};
tokens.forEach((token) => {
token.addEventListener("mouseenter", handler);
});
return () => {
tokens.forEach((token) => {
token.removeEventListener("mouseenter", handler);
});
};
}, [content]);
This should handle the interactions for you. Sorry for mixing class components and functional components with hooks, but you can achieve the same thing with class components (using componentDidMount and componentDidUpdate) as well. Using hook is just more elegant.
Currently, I am making a private messaging feature for a React app. I'm fairly new to React, so I'm not sure where I'm messing this up. Also, please note: For this particular project, I am unable to use jQuery/Redux/etc... just plain React.
So before I show my code, this is what results I have now:
The sent messages appear ordered properly, and the received messages are ordered properly, BUT it shows all sent messages before then showing all received messages. I would like for them all to display in the order that they were sent, regardless of which user sent it (think of how your average texting app works)
Now for my code (sorry I included a lot, I'm not sure where in the process it is messing up):
data.json
"privateMessages": [
{
"userId": 2,
"receiverId": 3,
"message": "first",
"id": 1
},
{
"userId": 3,
"receiverId": 2,
"message": "second",
"id": 2
},
{
"userId": 2,
"receiverId": 3,
"message": "third",
"id": 3
},
{
"userId": 2,
"receiverId": 3,
"message": "fourth",
"id": 4
},
{
"userId": 3,
"receiverId": 2,
"message": "fifth",
"id": 5
}
],
"users": [
{
"name": "User 1",
"id": 2
},
{
"name": "User 2",
"id": 3
}
MsgCard.js --- I suspect the problem is here but not sure.
export const MsgCard = ({message}) => {
const currentUserId = sessionStorage.getItem("nutshell_user");
if (message.sentBySelf) {
return (
<div className="sentMsg">
<h4>
<span className="nameOfSender">{message.user?.name}: </span>
{`${message.message}`}
</h4>
</div>
)
} else if (message.receiverId === parseInt(currentUserId)) {
return (
<div className="receivedMsg">
<h4>
<span className="nameOfSender">{message.user?.name}: </span>
{`${message.message}`}
</h4>
</div>
)
}
}
MsgList.js
export const MsgList = () => {
const [messages, setMessages] = useState([])
const currentUserId = sessionStorage.getItem("nutshell_user");
const getAllPMs = () => {
return fetch(`${remoteURL}/privateMessages/?_expand=user`)
.then(res=>res.json())
}
const scrollToEnd = () => {
const container = document.querySelector(".messagesContainer")
container.scrollTop = container.scrollHeight
}
const getPMs = () => {
getAllPMs().then(allPMs => {
const sentByCurrent = allPMs.filter(message => message.userId === parseInt(currentUserId))
const sentByOthers = allPMs.filter(message => message.userId !== parseInt(currentUserId))
const newCurrent = sentByCurrent.map(message => {
message.sentBySelf = true
return message
})
const newOthers = sentByOthers.map(message => {
message.sentBySelf = false
return message
})
const allMessages = newCurrent.concat(newOthers)
return allMessages
})
.then(allMsgsArray => {
setMessages(allMsgsArray)
})
.then(() => {
scrollToEnd()
})
}
useEffect(() => {
getPMs()
},[])
if (messages.length > 0) {
return (
<>
<div className="messagesContainer">
{messages.map(message => {
return <MsgCard key={message.id} message={message} />
})}
</div>
IGNORE THIS COMPONENT<MsgInput renderList={getPMs} />
</>
)
} else {
return (
<>
<div className="messagesContainer">
</div>
IGNORE THIS COMPONENT <MsgInput renderList={getPMs} />
</>
)
}
}
Your issue is how you handle adding the sentBySelf attribute to each message:
getAllPMs().then(allPMs => {
const sentByCurrent = allPMs.filter(message => message.userId === parseInt(currentUserId))
const sentByOthers = allPMs.filter(message => message.userId !== parseInt(currentUserId))
const newCurrent = sentByCurrent.map(message => {
message.sentBySelf = true
return message
})
const newOthers = sentByOthers.map(message => {
message.sentBySelf = false
return message
})
const allMessages = newCurrent.concat(newOthers)
return allMessages
})
You filter all sentByCurrent then all sentByOthers then when you rebuild the list you concat current with others. Ensuring all current come before all others.
You can use map instead to add the attribute without affecting the order.
const allPMs = [
{
"userId": 2,
"receiverId": 3,
"message": "first",
"id": 1
},
{
"userId": 3,
"receiverId": 2,
"message": "second",
"id": 2
},
{
"userId": 2,
"receiverId": 3,
"message": "third",
"id": 3
},
{
"userId": 2,
"receiverId": 3,
"message": "fourth",
"id": 4
},
{
"userId": 3,
"receiverId": 2,
"message": "fifth",
"id": 5
}
];
const currentUserId = "2";
const orderMaintained = allPMs.map(curr => ({...curr, sentBySelf: curr.userId === parseInt(currentUserId)}));
console.log(orderMaintained);
In your program this would look something like:
getAllPMs().then(allPMs => {
return allPMs.map(curr => ({...curr, sentBySelf: curr.userId === parseInt(currentUserId)}));
})
Add sentBySelf for the current object, so you will keep the sequence.
getAllPMs()
.then((allPMs) =>
allPMs.privateMessages.map((msg) => ({
...msg,
msg.userId === parseInt(currentUserId),
}))
) [...]
Here a live example:
https://codesandbox.io/s/ecstatic-hamilton-uck5n?fontsize=14&hidenavigation=1&theme=dark
Here is my React component:
const ChartItem = ({ id, apiUrl }) => {
const [nivoChartData, setNivoChartData] = useState([]);
//
//declare the API call
const apiCallAndConversionForNivoFormat = useCallback(async () => {
try {
const response = await axios.get(apiUrl);
console.log("response: ");
console.log(response);
//converting api response into the format needed by nivo charts
const dataConvertedForNivo = [
{
id: response.data.symbol,
color: "hsl(90, 70%, 50%)",
data: response.data.historical.forEach((key) => {
key["x"] = key["date"];
key["y"] = key["close"];
delete key["date"];
delete key["close"];
}),
},
];
console.log("dataConvertedForNivo: ");
console.log(dataConvertedForNivo);
setNivoChartData(dataConvertedForNivo);
} catch (e) {
console.error(e);
}
}, [setNivoChartData, apiUrl]);
useEffect(() => {
apiCallAndConversionForNivoFormat();
}, [apiCallAndConversionForNivoFormat]);
return (
<div className="chart-item">
<NivoLineChart key={id} nivoData={nivoChartData} />
</div>
);
};
The logs:
The original API response format before modifying:
{
"symbol": "AAPL",
"historical": [
{
"date": "2021-02-24",
"close": 125.349998
},
{
"date": "2021-02-23",
"close": 125.860001
},
{
"date": "2021-02-22",
"close": 126
},
]
}
^ I believe the response log is now showing "x" and "y" instead of "date" and "close" due to memoization.
nivo chart example format that I need to convert to:
[
{
"id": "AAPL",
"color": "hsl(90, 70%, 50%)",
"data": [
{
"x": "2021-02-24",
"y": 125.349998
},
{
"x": "2021-02-23",
"y": 125.860001
},
{
"x": "2021-02-22",
"y": 126
},
]
}
]
Can anyone understand why the dataConvertedForNivo.data is undefined? And is there any better way to do this response conversion?
You need to replace forEach with map.
const dataConvertedForNivo = [
{
id: response.data.symbol,
color: "hsl(90, 70%, 50%)",
data: response.data.historical.map(key => {
key["x"] = key["date"];
key["y"] = key["close"];
delete key["date"];
delete key["close"];
return key;
}),
},
];
I am building a drag and drop application -- that is given a multidimensional array of supported file type and titles for those file types and icons to use against them in a legend. The drag and drop picks up an accept array that has specific mime types -- I need to display to the user in easy terms what file types are allowed -- so return a comma delimited string - jpg, pdf
what is the best way of looping through the multidimensional array to get at the key in the forms to complete this task?
getAcceptedFileTypes(){
let supportedFiles = [{
"images": {
"icon": <ImageIcon />,
"formats": [{"png": "image/png"}, {"jpeg": "image/jpeg"}],
}
},{
"compressed_files": {
"icon": <DescriptionIcon />,
"formats": [{"zip": "application/x-zip-compressed"}, {"rar": "application/x-rar-compressed"}],
}
},{
"documents": {
"icon": <FileCopyIcon />,
"formats": [{"pdf": "application/pdf"}, {"docx": "application/msword"}, {"doc": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}],
}
}];
let accept = ["application/pdf","image/jpeg"]
console.log("supportedFiles", supportedFiles);
console.log("accept", accept);
let acceptedFiles = "jpeg, pdf";
return (
acceptedFiles
)
}
You could do something like:
let supportedFiles = [{
"images": {
"icon": "<ImageIcon />",
"formats": [{
"png": "image/png"
}, {
"jpeg": "image/jpeg"
}],
}
}, {
"compressed_files": {
"icon": "<DescriptionIcon />",
"formats": [{
"zip": "application/x-zip-compressed"
}, {
"rar": "application/x-rar-compressed"
}],
}
}, {
"documents": {
"icon": "<FileCopyIcon />",
"formats": [{
"pdf": "application/pdf"
}, {
"docx": "application/msword"
}, {
"doc": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
}],
}
}];
let accept = ["application/pdf", "image/jpeg"];
const acceptedFiles = supportedFiles.reduce((acc, item) => {
const subItem = Object.values(item)[0];
subItem.formats.forEach((format, index) => {
if (accept.indexOf(Object.values(format)[0]) > -1) {
acc.push(Object.keys(subItem.formats[index])[0]);
}
});
return acc;
}, []).join(', ');
//test
console.log(acceptedFiles);
You mean this?
const getAcceptedFileTypes = () => {
let supportedFiles = [{
"images": {
"icon": `<ImageIcon />`,
"formats": [{
"png": "image/png"
}, {
"jpeg": "image/jpeg"
}],
}
}, {
"compressed_files": {
"icon": `<DescriptionIcon />`,
"formats": [{
"zip": "application/x-zip-compressed"
}, {
"rar": "application/x-rar-compressed"
}],
}
}, {
"documents": {
"icon": `<FileCopyIcon />`,
"formats": [{
"pdf": "application/pdf"
}, {
"docx": "application/msword"
}, {
"doc": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
}],
}
}];
let acceptedFiles = supportedFiles.flatMap(file => file[Object.keys(file)[0]].formats)
return (
acceptedFiles
)
}
console.log(getAcceptedFileTypes())
console.log(getAcceptedFileTypes().map(entry => Object.keys(entry)[0]).join(","))
Might wanna try this
let supportedFiles = [{
"images": {
"icon": '<ImageIcon />',
"formats": [{"png": "image/png"}, {"jpeg": "image/jpeg"}],
}
},{
"compressed_files": {
"icon": '<DescriptionIcon />',
"formats": [{"zip": "application/x-zip-compressed"}, {"rar": "application/x-rar-compressed"}],
}
},{
"documents": {
"icon": '<FileCopyIcon />',
"formats": [{"pdf": "application/pdf"}, {"docx": "application/msword"}, {"doc": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}],
}
}];
let acceptedFiles=[];
supportedFiles.forEach((fileType)=>{
Object.keys(fileType).forEach(key=>{
fileType[key].formats.forEach(format=>{
acceptedFiles.push(Object.keys(format));
})
})
})
console.log(acceptedFiles.join(","))
If you change the structure then:
let supportedFilesObj ={
"images": {
"icon": '<ImageIcon />',
"formats": [{"png": "image/png"}, {"jpeg": "image/jpeg"}],
},
"compressed_files": {
"icon": '<DescriptionIcon />',
"formats": [{"zip": "application/x-zip-compressed"}, {"rar": "application/x-rar-compressed"}],
},
"documents": {
"icon": '<FileCopyIcon />',
"formats": [{"pdf": "application/pdf"}, {"docx": "application/msword"}, {"doc": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}],
}
};
let acceptedFiles=[];
Object.keys(supportedFilesObj).forEach((key)=>{
supportedFilesObj[key].formats.forEach(format=>{
acceptedFiles.push(Object.keys(format));
})
})
console.log(acceptedFiles.join(","))
Here is a simple solution using 3 nested for loops.
function getAcceptedFileExtensions() {
let acceptedExtensions = [];
for (let fileTypeObject of supportedFiles) {
for (let fileTypeKey of Object.keys(fileTypeObject)) {
for (let extensionPair of fileTypeObject[fileTypeKey].formats) {
acceptedExtensions.push(Object.keys(extensionPair)[0]);
}
}
}
return acceptedExtensions;
}
console.log(getAcceptedFileExtensions().toString());
The data structure is a bit weird as it contains an array of objects containing one key, which seems to be the name of each object, instead of e.g. an object with the different file-type-categories directly. Because of that the second loop could be shortened to Object.keys(fileTypeObject)[0]:
const supportedFiles = [
{
"images": {
"icon": "<ImageIcon />",
"formats": [
{ "png": "image/png" },
{ "jpeg": "image/jpeg" }
],
}
},
{
"compressed_files": {
"icon": "<DescriptionIcon />",
"formats": [
{ "zip": "application/x-zip-compressed" },
{ "rar": "application/x-rar-compressed" }
],
}
},
{
"documents": {
"icon": "<FileCopyIcon />",
"formats": [
{ "pdf": "application/pdf" },
{ "docx": "application/msword" },
{ "doc": "application/vnd.openxmlformats-officedocument.wordprocessingml.document" }
],
}
}
];
function getAcceptedFileExtensions() {
let acceptedExtensions = [];
for (let fileTypeObject of supportedFiles) {
let fileTypeKey = Object.keys(fileTypeObject)[0];
for (let extensionPair of fileTypeObject[fileTypeKey].formats) {
acceptedExtensions.push(Object.keys(extensionPair)[0]);
}
}
return acceptedExtensions;
}
console.log(getAcceptedFileExtensions().toString());
If this is an recurring operation, you can create a mapper object which maps each MIME type to its file extension name
const mapper = {}
for (const file of supportedFiles) {
const { formats } = Object.values(file)[0]
for (const format of formats) {
const [key, value] = Object.entries(format)[0]
mapper[value] = key;
}
}
function getAcceptedFiles(accept, mapper) {
return accept.map(t => mapper[t])
}
Mapper object:
{
"image/png": "png",
"image/jpeg": "jpeg",
"application/x-zip-compressed": "zip",
"application/x-rar-compressed": "rar",
"application/pdf": "pdf",
"application/msword": "docx",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "doc"
}
Here's a snippet:
const supportedFiles=[{images:{icon:"",formats:[{png:"image/png"},{jpeg:"image/jpeg"}],}},{compressed_files:{icon:"",formats:[{zip:"application/x-zip-compressed"},{rar:"application/x-rar-compressed"}],}},{documents:{icon:"",formats:[{pdf:"application/pdf"},{docx:"application/msword"},{doc:"application/vnd.openxmlformats-officedocument.wordprocessingml.document"}],}}];
const mapper = {}
for (const file of supportedFiles) {
const { formats } = Object.values(file)[0]
for (const format of formats) {
const [key, value] = Object.entries(format)[0]
mapper[value] = key;
}
}
function getAcceptedTypes(accept, mapper) {
return accept.map(t => mapper[t])
}
console.log( getAcceptedTypes( ["application/pdf","image/jpeg"], mapper) )
console.log( getAcceptedTypes( ["application/x-rar-compressed"], mapper) )
What I want to achieve is that if any fleet_id in fleetArray exist in om object then I want to remove it from om object.
Is there any better way to do this?
var newObject= {}
newObject.data=[]
var om = {
"message": "Successful",
"status": 200,
"data": [{
"tag": "",
"array": [
{
"type": 0,
"fleet_id": 23508,
},
{
"type": 10,
"fleet_id": 235089,
}
]
}, {
"tag": "",
"array": [{
"type": 320,
"fleet_id": 23218,
}]
}]
}
var fleetArray = ["23218","23508"];
om.data.forEach(function(api){
//console.log(api)
(api.array).forEach(function(data1){
fleetArray.forEach(function(fleet){
if(fleet==data1.fleet_id){
newObject.data.push(data1)
}
})
})
})
console.log(newObject)
You could use map and filter
om.data = om.data.map(e => {
e.array = e.array.filter(a => ! fleetArray.includes("" + a.fleet_id))
return e;
});
var om = {"message": "Successful","status": 200,"data": [{"tag": "","array": [{"type": 0,"fleet_id": 23508,},{"type": 10,"fleet_id": 235089,}]}, {"tag": "","array": [{"type": 320,"fleet_id": 23218,}]}]}
var fleetArray = ["23218","23508"];
om.data = om.data.map(e => {
e.array = e.array.filter(a => ! fleetArray.includes("" + a.fleet_id))
return e;
});
console.log(om);