How to pass DotNetObjectReference to JS DOM-event

I am trying to utilise JS drag & drop in Blazor, which works fine in general but I want to set a custom drag image during the ondragstart event. In general my code looks like this:

<div class="some-draggable-container"
     draggable="true"
     ondragstart="Element.dragStartHandler(event, '@(ImageSrcBase64)')" >
</div>
Element.dragStartHandler = function(event, imgSrcBase64) {
    var img = new Image();
    img.src = imgSrcBase64;
    event.dataTransfer.setDragImage(img, 0, 0);
}

The problem occurring to me is that I need to call a .Net function after setting the drag image and I cannot find a way to pass the needed DotNetObjectReference through to the JS part.

Simply passing the newly created objectRef into the JS event call leads to an Unexpected end of input error.

ondragstart="Element.dragStartHandler(event, '@(ImageSrcBase64)', @(DotNetObjectReference.Create(this)))"

Also using the JsonSerializer does not do the trick. It surely does serialise the object and JS is able to deserialise it, but as expected the DotNet.invokeMethod() methods are not present.

ondragstart="Element.dragStartHandler(event, '@(ImageSrcBase64)', @(JsonSerializer.Serialize(DotNetObjectReference.Create(this))))"

Utilising the Blazor event and handling it fully in .Net does not offer the ability to set the drag image because the passed DragEventArgs are not fully compliant to the JS one.

Passing the event args through IJSRuntime into a JS function leads to errors because it’s just not the same thing as the native JS event, so at least the setDragImage() Method is missing.

Is there any way to make this work? I don’t want to juggle around with JS-to-static-.Net calls and guids or that kind of workaround.

How will i filter sitemap urls by last modification date of today in google app script?

with the code below am able to retrieve a site’s sitemap urls and last modification dates. the problem is that there are over 600 urls retrieved, how will i filter in the script to only show urls with the last modification date of today, removing urls with old dates?

var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(‘Sheet1’);

//Create function that fires when menu item clicked.

function getLinks() {

var xml = UrlFetchApp.fetch(‘https://example.com/blog_listing-sitemap.xml’).getContentText();

var xml = XmlService.parse(xml);

var root = xml.getRootElement();

var ns = XmlService.getNamespace(‘http://www.sitemaps.org/schemas/sitemap/0.9’);

    //Get list of sitemap urls

    var sitemaps = root.getChildren();//sitemap

    //for each sitemap URL

    for (i = 0; i < sitemaps.length; i++) {

      //Get child elements of sitemap element

      var sitemap = sitemaps[i].getChildren();

      //For each child element of sitemap element

      for (a = 0; a < sitemap.length; a++) {

        var element = sitemap[a];

        //Find loc element for sitemap URL

        if (element.getName() === 'loc') {


         // xml = loadXML(element.getText());

          appendRows(xml.getRootElement().getChildren());

        }
      
   else if (root.getName() === 'urlset') {//if sitemap is url sitemap.

    appendRows(root.getChildren());

                   }

                 }

               }

           }

function appendRows(items) {

var urls = [];

var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(); //to write rows

//var filtered = data.filter(function (row) {

// return row[1].getFullYear() === 2016;

// });

for (var i = 0; i < items.length; i++) {

var children = items[i].getChildren();

var row = [];

for (var a = 0; a < children.length; a++) {

  var child = children[a];

  if (child.getChildren().length === 0) {

    row.push(child.getText());

   // row.filter(items)

  }

}

urls.push(row);

}

//write rows to sheet

sheet.getRange(sheet.getLastRow() + 1, 1, urls.length, urls[0].length).setValues(urls);

}

Create a computed JSON array in JS with multiple variables

First off, apologies if this is normally a simple thing, but I’m not particularly experienced in JS. I’m trying to make some graphs in Plotly.js for a work site that currently holds raw JSON. We have a JSON in the format:

stuff = [{"name": "shark", "location": "somewhere", "number":10},
         {"name": "shark", "location": "somewhereelse", "number":50},
         {"name": "shark", "location": "somewhere", "number":25},
         {"name": "turtle", "location": "anotherplace", "number":1},
         {"name": "elephant", "location": "greatplace", "number":50},
         {"name": "elephant", "location": "greatplace", "number":75}

And I need the result to look like:

computed = [{"name":"shark", "location":"somewhere", "number":35},
            {"name":"shark", "location":"somewhereelse", "number":50},
            {"name":"turtle", "location":"anotherplace", "number":1},
            {"name":"elephant", "location":"greatplace", "number":125}

Where all names are grouped by location and all numbers in that group are summed. It is then this computed JSON that I’ll be using to graph with Plotly.js with some functions I have already built.

I think I can simplify the problem as:

forEach((item) => {
x.push(item['location']
y.push(y += stuff.number where stuff.location === x[-1])
}

But this also means I’ll get the same number of rows as in stuff, just computed and graphed. I’m afraid I can’t figure it out any further.

Any help would be muchly appreciated.

Everytime I test my attributes are undefined?

I want to create a class Deck that gets two attributes id and remaining. I use the Deck of Cards API to get the information of a deck but every time I create a Deck I keep getting id and remaining as undefined and I don’t understand why because the JSON value is good and when I print it I got something but my attributes are undefined.

 class Deck {

    constructor(numberOfDeck, jokersEnabled) {
        let url;

        if (jokersEnabled) {
            url = "https://www.deckofcardsapi.com/api/deck/new/shuffle/?deck_count=" + numberOfDeck + "&jokers_enabled=true";
        } else {
            url = "https://www.deckofcardsapi.com/api/deck/new/shuffle/?deck_count=" + numberOfDeck;
        }
        console.log(url);
        fetch(url).then(res => res.json()).then(value => {
            this.id = value.deck_id;
            this.remaining = value.remaining;
        }).catch(function(err) {
            console.log(err);
        });
    }
}

let deck = new Deck(1, true);
console.log(deck.id + " " + deck.remaining);

How to join javascript array elements without forloop

I have from a mongoose query result:

{
    "store": [
        {
            "items": [
                "A1",
                "A2"
            ]
        },
        {
            "items": [
                "A3",
                "A4"
            ]
        },
        {
            "items": [
                "B1",
                "B2"
            ]
        },
        {
            "items": [
                "B3",
                "B4"
            ]
        },
        {
            "items": [
                "C8",
                "C9",
                "C10"
            ]
        }
    ]
}

I need this: [“A1″,”A2″,”A3″,”A4″,”B1″,”B2″,”B3″,”B4″,”C8″,”C9”,C10]
Is there any way to do this without using foreach loop, as my array will be so long and it will be time consuming.

Refresh Jqgrid in PHP

I have jqgrid that need to refresh data onchange event, i create table with js and make object of jqgrid like this:

$('<table id="list2"></table>' +
    '<div id="gridpager"></div>').appendTo('#topics');
grid = jQuery("#list2");

after this, I have an ajax function to get data from the database and I put jqgrid on the success method. here is the code.

function getReport(start_date,end_date) {
    $.ajax({
        url: "logics/inventory_reports",
        type: "POST",
        data: {
            type: "getTrailBalance_report",
            start_date: start_date,
            end_date: end_date,
        },
        success: function (data) {
            let dt = JSON.parse(data);
            debugger;
            grid.jqGrid({
                datastr: dt.records,
                datatype: "jsonstring",
                height: "auto",
                loadui: "disable",
                pgbuttons : false,
                pginput : false,
                colNames: [/*"id",*/"Items","Debit", "Credit"],
                colModel: [
                    //{name: "id",width:1, hidden:true, key:true},
                    {name: "name", width:250, resizable: false,sortable: false},
                    {name: "debit",width:150,sortable: false},
                    {name: "credit",width:150,sortable: false}
                ],
                treeGrid: true,
                pager : '#gridpager',
                caption: "Trail Balance Report",
                ExpandColumn: "elementName",
                autowidth: true,

                rowNum: 10000,
                jsonReader: {
                    root: "response"
                }
            }).navGrid('#gridpager',{
                view:true,
                del:false,
                search: false,
                autoRefresh: true,
            });
            jQuery("#list2").trigger("reloadGrid");

        }
    });
}

and here is my dropdown onchange event.

<select name="time_period" id="time_period" class="form-control" onchange="getTimePeriod()">
                        <option value="0">--Select Time Period--</option>
                        <option value="cDay">Current Day</option>
                        <option value="lDay">Last Day</option>
                        <option value="cWeek">Current Week</option>
                        <option value="lWeek">Last Week</option>
                        <option value="cMonth">Current Month</option>
                        <option value="lMonth">Last Month</option>
                        <option value="cYear">Current Year</option>
                        <option value="lYear">Last Year</option>
                    </select>

here is the code of getTimePeriod() method from where I call the getReport method with passing parameters.

function getTimePeriod() {

    let timePeriod = $("#time_period").val();
    let periodDate = new Date();
    let date = new Date(), y = date.getFullYear(), m = date.getMonth();
    let message = "";
    let FYear;
    let start_date = new Date();
    debugger;
    switch (timePeriod) {

        case 'cDay':
            periodDate = new Date();
            message = 'Current Day';
            break;

        case 'lDay':
            //periodDate = new Date;
            start_date.setDate(start_date.getDate() - 1);
            periodDate.setDate(periodDate.getDate() - 1);
            // periodDate = periodDate.toISOString().slice(0, 10);
            message = 'Last Day';
            break;

        case 'cWeek':
            //periodDate = new Date;
            start_date.setDate(start_date.getDate() - (start_date.getDay() + 6) % 7); // Starting date of week
            periodDate.setDate(periodDate.getDate() - (periodDate.getDay() - 7) % 7); // Ending date of Week
            message = 'Current Week';
            break;

        case 'lWeek':
            start_date.setDate(start_date.getDate() - (start_date.getDay() + 6) % 7);// Starting date.
            start_date.setDate(start_date.getDate() - 7);
            periodDate.setDate(periodDate.getDate() - (periodDate.getDay() -  7) % 7); // Ending date.
            periodDate.setDate(periodDate.getDate() - 7);
            message = 'Last Week';
            break;

        case 'cMonth':
            start_date = new Date(y, m, 1); // Starting date of this month.
            periodDate = new Date(y, m + 1, 0); // Ending date of this month.
            message = 'Current Month';
            break;

        case 'lMonth':
            start_date = new Date(y, m - 1, 1); // Starting date of the previous Month.
            periodDate = new Date(y, m, 0); // Ending date of the previous Month.
            message = 'Last Month';
            break;

        case 'cYear':
            FYear = getFinancialYearsLastMonth();
            start_date = new Date(y, FYear, 1); // Starting date of this Financial Year.
            periodDate = new Date(y +1, FYear, 0); /*#### second value tells the month number ######*/ // Ending Date.
            message = 'Current Year';
            break;

        case 'lYear':
            FYear = getFinancialYearsLastMonth();
            start_date = new Date(y - 1, FYear, 1); // Starting date of previous Financial Year.
            periodDate = new Date(y, FYear, 0); /*#### second value tells the month number ######*/ // Ending Date
            message = 'Last Year';
            break;

    }

    // periodDate = periodDate.toISOString().slice(0, 10);
    document.getElementById("showDate").innerHTML = getDateInFormat(periodDate);
    getReport(ReFormateDate(start_date),ReFormateDate(periodDate));

}

avoid the rest code from getTimePeriod method just see the calling of getReport.

I put debugger and test that every time the data is updated but jqgrid is not refreshing the data. I tried but like jQuery(“#list2”).trigger(“reloadGrid”); and .navGrid(‘#gridpager’,{
view:true,
del:false,
search: false,
autoRefresh: true,
}); but no effected. Can you help me out with this issue, please?
Thanks!

Lower cost alternative to try/catch blocks in node.js

I have a router.js file in my node.js application which almost all my routes are like the following code:

router.get('/some-url', async(req, res) => {
    try {
       // Done some asynchronous work
    } catch (error) {
       // Catch errors
    }
})

As you can see my callback function is asynchronous and to make sure there isn’t any uncaught errors, I’m using try/catch blocks.
But I know each try/catch block is a new costly operation when it comes to CPU time.
You can see why such a thing can be problematic in a real application.
So I’m just wondering is there any better way to implement this logic with lower CPU cost?

Thank you in advance

Too many re render Protected Route -ReactJS

I am new to react and I tried to make Protected routes which works perfectly on local but on server it gives the error.enter image description here

my Code is as follows

Protected Route

import React from "react";
import { Redirect, Route } from "react-router-dom";

function ProtectedRoute({ component: Component, ...restOfProps }) {
    const token = localStorage.getItem("token");
    const userId = localStorage.getItem('userId');  
    return (
      <Route
        {...restOfProps}
        render={(props) =>
          token && userId ? <Component {...props} /> : <Redirect to="/login" />
        }
      />
    );
  }
  
  export default ProtectedRoute;

Main Component

import React, { Component } from "react";
import Navbar from "../Shared/Navbar";
import List from "./ListComponent";
import Login from "./LoginComponent";
import { BrowserRouter as Router, Route, Switch, Redirect } from "react-router-dom";
import Dashboard from "./Dashboard";
import Item from "./Item";
import ProtectedRoute from "./ProtectedRoute";

class Main extends Component {
    constructor(props) {
        super(props);
        // this.state = {
        //     token: '',
        //     userId: ''
        // }
        // this.handleData = this.handleData.bind(this);
        this.handleLogout = this.handleLogout.bind(this);
    }

    // handleData(token, userId) {
    //     this.setState({ token: token, userId: userId });
    //     localStorage.setItem('token', token);
    //     localStorage.setItem('userId', userId);
    //     window.location='/';
    // }

    handleLogout(){
        this.setState({token: ''})
        this.setState({userId:'' })
        localStorage.setItem('userId','')
        localStorage.setItem('token', '');
    }
    render() {
        return (
            <>
                <Router>
                    <Navbar handleLogout={this.handleLogout}/>
                    <Switch>
                        <ProtectedRoute exact path ={["/home","/"]} component={Dashboard} />
                        <ProtectedRoute exact path ="/list" component={List} />
                        <ProtectedRoute exact path ="/item" component={Item} />
                        <ProtectedRoute exact path ="/item/:id" component={Item} />
                        {/*<Route path="/login" component={Login}/>*/}
                        {
                            localStorage.getItem('token') === '' && localStorage.getItem('userId') === ''
                            ?<Route exact path="/login" component={Login} />
                            :<Redirect to='/'/>
                        }
                    </Switch>
                </Router>
            </>
        );
    }
}

export default Main;

Here when i comment protected Route condition it works on server but the login page is accessible.

LoginComponent

import React, {Component} from "react";
import api from "../../http-common";

class Login extends Component {
    constructor(props) {
        super(props);
        this.state = {
            username: '',
            password: '',
            // tokenData: ''
        }
        this.handleLogin = this.handleLogin.bind(this);
        this.handleUsername = this.handleUsername.bind(this);
        this.handlePassword = this.handlePassword.bind(this);
    }

    handleUsername(e){
        if(e.target.value.length > 0){
            this.setState({username: e.target.value})
        }
    }

    handlePassword(e){
        this.setState({password: e.target.value})
    }

    handleLogin(e){
        e.preventDefault();
        this.login(this.state.username, this.state.password);
    }
    async login(username, password) {
        const formData = new FormData();
        formData.append('username', username);
        formData.append('password',password);
        await api.post('/api/login', formData)
            .then(response => {
                if (response.status === 200 && response.data.token !== '') {
                    // console.log(response.data)
                    localStorage.setItem('token', response.data.token);
                    localStorage.setItem('userId', response.data.userId);
                    window.location='/'
                    // this.setState({tokenData: response.data.token});
                    // this.props.handleData(this.state.tokenData, this.state.username);
                } else if (response.status === 200 && response.data.token === '' && response.data.message === 'User not Found') {
                    alert(response.data.message)
                } else if (response.status === 200 && response.data.token === '' && response.data.message === 'User is not valid') {
                    alert(response.data.message)
                } else {
                    console.log(response.statusText);
                }
            })
            .catch((error) => console.log(error))
    }
    render() {
        return (
            <>
                <form onSubmit={this.handleLogin}>
                    <div className="container">
                        <div className="d-flex justify-content-center mt-3">
                            <div className="card mt-3 mx-3 px-3 py-3">
                                <div className="mx-1">
                                    <div className="form-group row">
                                        <label htmlFor="username" className="mr-2">Username</label>
                                        <div className="m-auto">
                                            <input
                                                type="text"
                                                id="username"
                                                name="username"
                                                className="form-control mb-3"
                                                placeholder="Username"
                                                required="required"
                                                onChange={this.handleUsername}
                                            />
                                        </div>
                                    </div>

                                    <div className="form-group row">
                                        <label htmlFor="password" className="mr-2">Password</label>
                                        <div className="mx-auto">
                                            <input
                                                type="password"
                                                id="password"
                                                name="password"
                                                className="form-control"
                                                placeholder="Password"
                                                required="required"
                                                onChange={this.handlePassword}
                                            />
                                        </div>
                                    </div>

                                    <div className="form-group">
                                        <button type="submit" className="btn btn-primary btn-block">Log in</button>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </form>
            </>
        );
    }
}

export default Login;

Please Help, Thank You.

WebRTC conncet with SFU server failed using Lite ICE

I’m trying to connect my web client with my SFU server. And the SFU server implements lite ICE.
Here’s the SDP sent by my web client:

v=0
o=- 1250414714658974016 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio
a=msid-semantic: WMS RNSq70GfxaWKMGzvpJcEAqpMw9dnbB5U1N9a
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:h1kO
a=ice-pwd:aXsis+1NfXMwOmc5ICjAH0NC
a=ice-options:trickle
a=fingerprint:sha-256 DA:6F:29:E4:6B:89:76:F9:F1:BD:E0:75:BB:EB:D2:54:0B:C8:83:54:BA:C4:E2:67:E1:FF:38:DD:D2:17:8C:74
a=setup:actpass
a=mid:audio
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=sendrecv
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
a=rtpmap:103 ISAC/16000
a=rtpmap:104 ISAC/32000
a=rtpmap:9 G722/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:106 CN/32000
a=rtpmap:105 CN/16000
a=rtpmap:13 CN/8000
a=rtpmap:110 telephone-event/48000
a=rtpmap:112 telephone-event/32000
a=rtpmap:113 telephone-event/16000
a=rtpmap:126 telephone-event/8000
a=ssrc:3584188035 cname:Vx+7hyzjBBd0353j
a=ssrc:3584188035 msid:RNSq70GfxaWKMGzvpJcEAqpMw9dnbB5U1N9a 4428e230-46d2-4718-8f2b-05e0e05c084b
a=ssrc:3584188035 mslabel:RNSq70GfxaWKMGzvpJcEAqpMw9dnbB5U1N9a
a=ssrc:3584188035 label:4428e230-46d2-4718-8f2b-05e0e05c084b

Here’s the SDP sent by my SFU server:

v=0
o=- 7437866493835506893 2 IN IP4 10.1.29.248
s=-
t=0 0
a=group:BUNDLE audio
a=msid-semantic: WMS xzlDAum3wM3zhq0yidoOIw3xda3W45AWM0jd
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
c=IN IP4 10.1.29.248
a=rtcp:9 IN IP4 10.1.29.248
a=candidate:2999745851 1 udp 2122260223 10.1.29.248 60197 typ host
a=ice-ufrag:0ewh
a=ice-pwd:610Q94mNcZLoL5uVoSZyXKuW
a=ice-options:trickle
a=ice-lite
a=end-of-candidates
a=fingerprint:sha-256 48:53:40:64:CF:F8:8A:69:F8:CD:66:E0:A6:70:57:07:2A:DC:51:53:26:5C:BD:1A:F1:FD:05:B1:40:9F:63:D9
a=setup:active
a=mid:audio
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=sendrecv
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
a=rtpmap:103 ISAC/16000
a=rtpmap:104 ISAC/32000
a=rtpmap:9 G722/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:106 CN/32000
a=rtpmap:105 CN/16000
a=rtpmap:13 CN/8000
a=rtpmap:110 telephone-event/48000
a=rtpmap:112 telephone-event/32000
a=rtpmap:113 telephone-event/16000
a=rtpmap:126 telephone-event/8000
a=ssrc:3676579219 cname:2KRN6J2bznW2MyqZ
a=ssrc:3676579219 msid:xzlDAum3wM3zhq0yidoOIw3xda3W45AWM0jd 80ff593f-401e-4928-ad74-28e34923d9ad
a=ssrc:3676579219 mslabel:xzlDAum3wM3zhq0yidoOIw3xda3W45AWM0jd
a=ssrc:3676579219 label:80ff593f-401e-4928-ad74-28e34923d9ad

The pcap file captured by WireShark shows that SFU server send a BINDING SUCCESS response.
enter image description here
But the connectionState and iceConnectionState of my RTCPeerConnection is always “failed”.

enter image description here

I have checked the remoteDescription.sdp of my RTCPeerConnection object.
The line a=ice-lite disappeared.
enter image description here

What’s the problem? Is the SDP generated by my SFU server wrong?

Is there a way to highlight data points based on input with vega-lite?

I’m creating a scatterplot matrix with vega-lite, I want to add a functionality that allows users to search and select for specific data-points with a text input that uses that same dataset as the scatterplot and when selected highlight those points in the scatterplot. Based on my initial search i’ve yet to find a way to do so. Is this even possible?

Current implementation

Heres the current scatterplot code. implementation

var scatterPlot = {
        "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
        "title": "USDA Food Database",
        "data": {
        "url": "data/newData.json"
        },      
        "transform": [
            {"filter": "datum.ONIscore > 0 && datum.F6 != '' && datum.Protein != 'NULL' && datum.Fat != 'NULL'&& datum.Carb != 'NULL' && datum.Calorie != 'NULL'"}
        ],
        "concat": [
          {
            //ScatterPlot # 1
            "encoding": {
              "color": {
                  "condition": {
                  "param": "brush",
                  "title": "Food Categories",
                  "field": "F6",
                  "type": "nominal",
    
                  },
                  "value": "gray"
              },
              "tooltip": [
                  { "field": "foodName", "type": "nominal" },
                  { "field": "Protein", "type": "nominal" },
                  { "field": "Fat", "type": "nominal" },
                  { "field": "Carb", "type": "nominal" },
                  { "field": "Calorie", "type": "nominal" },
                  { "field": "ND", "type": "nominal" },
              ],
              "y": {
                  "field": "Protein",
                  "title": "Protein",
                  "type": "quantitative"
              },
              "x": {
                  "title": "ONIscore",
                  "field": "ONIscore",
                  "type": "quantitative"
              },
              },
              "width": 500,
              "height": 250,
              "mark": "circle",
              "params": [
                  {
                      "name": "brush",
                      "select": {
                      "type": "interval",
                      "resolve": "union",
                      "on": "[mousedown[event.shiftKey], window:mouseup] > window:mousemove!",
                      "translate": "[mousedown[event.shiftKey], window:mouseup] > window:mousemove!",
                      "zoom": "wheel![event.shiftKey]"
                      }
                  },
                  {
                      "name": "grid",
                      "select": {
                          "type": "interval",
                          "resolve": "global",
                          "translate": "[mousedown[!event.shiftKey], window:mouseup] > window:mousemove!",
                          "zoom": "wheel![!event.shiftKey]"
                      },               
                      "bind": "scales",
                  },
              ],
              "transform": [{"filter": {"param": "click"}}],
            },
         {
          "encoding": {
          "color": {
              "condition": {
              "param": "brush",
              "title": "Food Categories",
              "field": "F6",
              "type": "nominal",

              },
              "value": "gray"
          },
          "tooltip": [
              { "field": "foodName", "type": "nominal" },
              { "field": "Protein", "type": "nominal" },
              { "field": "Fat", "type": "nominal" },
              { "field": "Carb", "type": "nominal" },
              { "field": "Calorie", "type": "nominal" },
              { "field": "ND", "type": "nominal" },
          ],
          "y": {
              "field": "Fat",
              "title": "Fat",
              "type": "quantitative"
          },
          "x": {
              "title": "ONIscore",
              "field": "ONIscore",
              "type": "quantitative"
          },
          },
          "width": 500,
          "height": 250,
          "mark": "circle",
          "params": [
              {
                  "name": "brush",
                  "select": {
                  "type": "interval",
                  "resolve": "union",
                  "on": "[mousedown[event.shiftKey], window:mouseup] > window:mousemove!",
                  "translate": "[mousedown[event.shiftKey], window:mouseup] > window:mousemove!",
                  "zoom": "wheel![event.shiftKey]"
                  }
              },
              {
                  "name": "grid",
                  "select": {
                      "type": "interval",
                      "resolve": "global",
                      "translate": "[mousedown[!event.shiftKey], window:mouseup] > window:mousemove!",
                      "zoom": "wheel![!event.shiftKey]"
                  },               
                  "bind": "scales",
              },
          ],
          "transform": [{"filter": {"param": "click"}}],

        },
        //Scatterplot #3
        {
        "encoding": {
        "color": {
            "condition": {
            "param": "brush",
            "title": "Food Categories",
            "field": "F6",
            "type": "nominal",

            },
            "value": "gray"
        },
        "tooltip": [
            { "field": "foodName", "type": "nominal" },
            { "field": "Protein", "type": "nominal" },
            { "field": "Fat", "type": "nominal" },
            { "field": "Carb", "type": "nominal" },
            { "field": "Calorie", "type": "nominal" },
            { "field": "ND", "type": "nominal" },
        ],
        "y": {
            "field": "Carb",
            "title": "Carbohydrates",
            "type": "quantitative"
        },
        "x": {
            "title": "ONIscore",
            "field": "ONIscore",
            "type": "quantitative"
        }
        },
        "width": 500,
        "height": 250, 
        "mark": "circle",
        "params": [
            {
                "name": "brush",
                "select": {
                "type": "interval",
                "resolve": "union",
                "on": "[mousedown[event.shiftKey], window:mouseup] > window:mousemove!",
                "translate": "[mousedown[event.shiftKey], window:mouseup] > window:mousemove!",
                "zoom": "wheel![event.shiftKey]"
                }
            },
            {
                "name": "grid",
                "select": {
                    "type": "interval",
                    "resolve": "global",
                    "translate": "[mousedown[!event.shiftKey], window:mouseup] > window:mousemove!",
                    "zoom": "wheel![!event.shiftKey]"
                },               
                "bind": "scales",
            },
        ],
        "transform": [{"filter": {"param": "click"}}],

        },
        //Scatterplot #4
        {
          "encoding": {
          "color": {
              "condition": {
              "param": "brush",
              "title": "Food Categories",
              "field": "F6",
              "type": "nominal",
    
              },
              "value": "gray"
          },
          "tooltip": [
              { "field": "foodName", "type": "nominal" },
              { "field": "Protein", "type": "nominal" },
              { "field": "Fat", "type": "nominal" },
              { "field": "Carb", "type": "nominal" },
              { "field": "Calorie", "type": "nominal" },
              { "field": "ND", "type": "nominal" },
              { "field": "ONIscore", "type": "nominal" },
              { "field": "SatietyIndex", "type": "nominal" },
              { "field": "Satiety", "type": "nominal" },
          ],
          "y": {
              "field": "Calorie",
              "title": "Calories pr. 100 grams",
              "type": "quantitative"
          },
          "x": {
              "title": "ONIscore",
              "field": "ONIscore",
              "type": "quantitative"
          }
          },
          "width": 500,
          "height": 250, 
          "mark": "circle",
          "params": [
              {
                  "name": "brush",
                  "select": {
                  "type": "interval",
                  "resolve": "union",
                  "on": "[mousedown[event.shiftKey], window:mouseup] > window:mousemove!",
                  "translate": "[mousedown[event.shiftKey], window:mouseup] > window:mousemove!",
                  "zoom": "wheel![event.shiftKey]"
                  }
              },
              {
                  "name": "grid",
                  "select": {
                      "type": "interval",
                      "resolve": "global",
                      "translate": "[mousedown[!event.shiftKey], window:mouseup] > window:mousemove!",
                      "zoom": "wheel![!event.shiftKey]"
                  },               
                  "bind": "scales",
              },
          ],
          "transform": [{"filter": {"param": "click"}}],
    
        },
        //Scatterplot #5
        {
        "encoding": {
        "color": {
            "condition": {
            "param": "brush",
            "title": "Food Categories",
            "field": "F6",
            "type": "nominal",
    
            },
            "value": "gray"
        },
        "tooltip": [
            { "field": "foodName", "type": "nominal" },
            { "field": "Protein", "type": "nominal" },
            { "field": "Fat", "type": "nominal" },
            { "field": "Carb", "type": "nominal" },
            { "field": "Calorie", "type": "nominal" },
            { "field": "ND", "type": "nominal" },
        ],
        "y": {
            "field": "Carb",
            "title": "Carb",
            "type": "quantitative"
        },
        "x": {
            "title": "InsulinogenicV2",
            "field": "InsulinogenicV2",
            "type": "quantitative"
        }
        },
        "width": 500,
        "height": 250,
        "mark": "circle",
        "params": [
            {
                "name": "brush",
                "select": {
                "type": "interval",
                "resolve": "union",
                "on": "[mousedown[event.shiftKey], window:mouseup] > window:mousemove!",
                "translate": "[mousedown[event.shiftKey], window:mouseup] > window:mousemove!",
                "zoom": "wheel![event.shiftKey]"
                }
            },
            {
                "name": "grid",
                "select": {
                    "type": "interval",
                    "resolve": "global",
                    "translate": "[mousedown[!event.shiftKey], window:mouseup] > window:mousemove!",
                    "zoom": "wheel![!event.shiftKey]"
                },               
                "bind": "scales",
            },
        ],
        "transform": [{"filter": {"param": "click"}}],
    
        },
        //Scatterplot #6
        {
        "encoding": {
        "color": {
            "condition": {
            "param": "brush",
            "title": "Food Categories",
            "field": "F6",
            "type": "nominal",
      
            },
            "value": "gray"
        },
        "tooltip": [
            { "field": "foodName", "type": "nominal" },
            { "field": "Protein", "type": "nominal" },
            { "field": "Fat", "type": "nominal" },
            { "field": "Carb", "type": "nominal" },
            { "field": "Calorie", "type": "nominal" },
            { "field": "ND", "type": "nominal" },
        ],
        "y": {
            "field": "SatietyIndex",
            "title": "Satiety",
            "type": "quantitative"
        },
        "x": {
            "title": "Satiety",
            "field": "Satiety",
            "type": "quantitative"
        }
        },
        "width": 500,
        "height": 250,
        "mark": "circle",
        "params": [
            {
                "name": "brush",
                "select": {
                "type": "interval",
                "resolve": "union",
                "on": "[mousedown[event.shiftKey], window:mouseup] > window:mousemove!",
                "translate": "[mousedown[event.shiftKey], window:mouseup] > window:mousemove!",
                "zoom": "wheel![event.shiftKey]"
                }
            },
            {
                "name": "grid",
                "select": {
                    "type": "interval",
                    "resolve": "global",
                    "translate": "[mousedown[!event.shiftKey], window:mouseup] > window:mousemove!",
                    "zoom": "wheel![!event.shiftKey]"
                },               
                "bind": "scales",
            },
        ],
        "transform": [{"filter": {"param": "click"}}]
    },
        
        {
          //Barchart Begin
          "encoding": {
          "color": {
              "condition": {
              "param": "click",
              "field": "F6",
              },
              "value": "gray"
          },
          "x": {"aggregate": "count", "type": "nominal"},
          "y": {"title": "Food Category", "field": "F6"}
          },            
            //BARCHART 
            "width": 500,
            "mark": "bar",
            "params": [{
            "name": "click",
            "select": {"type": "point", "encodings": ["color"]}
            }],
            "transform": [{"filter": {"param": "brush"}}]
        }
        ],
        "config" : {
          "concat": {
         "spacing" : 0,
         "columns" : 2
       }
      } 
      }


        
await vegaEmbed('#scatterPlot', scatterPlot).then(function(result){
console.log(result.view.addEventListener('click',function(event,item){
sendDataToFile(item.datum,1);    
console.log("Sending data to JSON file.");
}));
})

Search bar code

const autoCompleteJS = new autoComplete({
    placeHolder: "Search for Food...",
    data: {
        src: async() => {
            try {
                // Loading placeholder text
                document.getElementById("autoComplete").setAttribute("placeholder", "Loading...");
                // Fetch External Data Source
                const source = await fetch("./data/data.json");
                const data = await source.json();
                // Post Loading placeholder text
                document.getElementById("autoComplete").setAttribute("placeholder", autoCompleteJS.placeHolder);
                // Returns Fetched data
                return data;
            } catch (error) {
                return error;
            }
        },
        keys: ["foodName"],
        cache: true,
    },
    resultItem: {
        highlight: true
    },
    events: {
        input: {
            selection: (event) => {
                const selection = event.detail.selection.value;
                autoCompleteJS.input.value = selection;
            }
        }
    }
});

Husky – does not start pre-commit?

I’m initializing git

git init

Installing hasky

npx husky-init && yarn

I get this package.json and pre-commit

{
  ...
  "scripts": {
    ...
    "prepare": "husky install",
    "lint": "eslint .",
    "lint:fix": "eslint --fix ."
  },
  "devDependencies": {
    ...
    "husky": "^7.0.0"
  },
  ...
}

.husky/pre-commit

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

yarn lint:fix

Making changes to git

git add .

Starting a commit

git commit -m “test”

Result:

[master (root commit) 05f4037] test
 17 files changed, 5495 insertions(+)
 create mode 100644 .env.example
 create mode 100644 .eslintignore
 create mode 100644 .eslintrc.js
 create mode 100644 .gitignore
 create mode 100755 .husky/pre-commit
 create mode 100644 .nvmrc
 create mode 100644 .prettierrc
 create mode 100644 jest.config.js
 create mode 100644 nodemon.json
 create mode 100644 package.json
 create mode 100644 src/__tests__/math/add.test.ts
 create mode 100644 src/index.ts
 create mode 100644 src/math/add.test.ts
 create mode 100644 src/math/add.ts
 create mode 100644 tsconfig.json
 create mode 100644 tsconfig.prod.json
 create mode 100644 yarn.lock

I make changes in any file, commit; the files are committed as usual.
I can’t see the reasons why.

Is there a better way to assign a class to multiple elements?

I’m trying to code a table with infinite horizontal scrolling and I need to assign a certain color pattern the each row, but the start position in such color pattern is not the same for each row.

As you can see in my code, row 0 has as eventListener that toggles its class and applies the color pattern (it’s a 35 cells color pattern).

I need to do it for 5 rows, but I had to attrib colors with 35 nth-child selectors for row 0 alone.

Do I really have to code all those 35 selectors or there’s a better way to do it?

I’m talking about class cRow0 and all those td:nth-child(35n + x).

Rows 1 to 4 have a different approach, and colors are assigned as the cells are created.

The color pattern is defined in:

const mColors = ["red","red","cyan","cyan","lime","lime","lime","lime","lime","red","red","red","lime","lime","lime","lime","lime","lime","cyan","cyan","cyan","lime","lime","lime","lime","lime","red","red","cyan","cyan","lime","lime","lime","lime","lime"];`

As the user scrolls to the left, an eventListener creates 1 cell per row and the color assign follows a correction defined in:

mRow_Correction = [0,1,2,3];

Actually in the final version that correction will be something like

mRow_Correction = [2,0,3,1];

Anyway, in this example I’m assigning colors via

let hCell = document.createElement("td");
iRow_Correction = mRow_Correction[(iRow - 1)];
let sColor = mColors[iRow_Correction];
hCell.setAttribute("style", "background-color: " + sColor + ";");

That seems to work, but the problem is: I don’t want to assign colors as the cells are created. I want to toggle the class, like I do for row 0.

For what I see, I’ll have to code 35 nth-child selectors for each row, but there should be a better way to do it… or there isn’t?…

    var iColumns = 1, iShift = 0;
    const mColors = ["red","red","cyan","cyan","lime","lime","lime","lime","lime","red","red","red","lime","lime","lime","lime","lime","lime","cyan","cyan","cyan","lime","lime","lime","lime","lime","red","red","cyan","cyan","lime","lime","lime","lime","lime"];
    
    const hRow0 = document.getElementById("idRow0");
    hRow0.addEventListener("click", function() {
        hRow0.classList.toggle("cRow0");        
    });
    
    const hDiv_Table = document.querySelector("#idDiv_Table");
    hDiv_Table.addEventListener("scroll", () => {
        if (hDiv_Table.scrollLeft + hDiv_Table.clientWidth >= hDiv_Table.scrollWidth) fCreate_Cell();
    });
    
    for (let iColumn = 1; iColumn < 11; iColumn++){
        fCreate_Cell();
    }
    
    function fCreate_Cell() {
        let iRow_Correction, mRow_Correction = [0,1,2,3];
        let iColumn = iColumns;
        for (let iRow = 0; iRow < 5; iRow++){
            let hRow = document.getElementById("idRow" + iRow);
            let sID = "r" + iRow + "c" + iColumn;
            let hCell = document.createElement("td");
            hCell.setAttribute("id", sID);
            hRow.appendChild(hCell);
            if (iRow == 0) {
                hCell.innerHTML = "col " + iColumns;
            } else {
                iRow_Correction = mRow_Correction[(iRow - 1)];
                ((iRow_Correction + iShift) < 35) ? iRow_Correction += iShift: iRow_Correction = (iRow_Correction + iShift) - 35;
                let sColor = mColors[iRow_Correction];
                hCell.innerHTML = "col " + iColumns + "<br>" + sColor;
                hCell.setAttribute("style", "background-color: " + sColor + ";");
            }
        }
        (iShift < 34) ? iShift++ : iShift = 0;
        iColumns++;
    }
    html {
        text-align: center;
    }
    
    .cDiv_Main {
        width:100%;
        height: 100%;  
        position: fixed;
        top: 0;
        left: 0;
        margin: 0;
    }
    
    .cDiv_Title {
        width: 100%;
        height: 15%;
        border: 1px solid black;
        background-color: blue;
        color: white;
        font-weight: bold;
        display: flex;
        justify-content: center;
        flex-direction: column;
    }
    
    .cDiv_Table {
        width: 100%;
        height: 85%;
        overflow: auto;
    }
    
    .cDiv_Main table {
        width: 100%;
        height: 100%;
        border-spacing: 0;
    }
    
    table tr {
        height: 20%;
    }
        
    table td {
        min-width: 50px;
        min-height: 20px;
        border: 1px solid black;
    }
    
    .cColum_Fixed_Row_Odd, .cColum_Fixed_Row_Even {
        position: -webkit-sticky;
        position: sticky;
        left: 0;
        font-weight: bold;
    }
    
    .cTable_Main tr:nth-child(2n+1) {
        background-color: white;
    }
    .cTable_Main tr:nth-child(2n) {
        background-color: lightgray;
    }
    
    
    .cColum_Fixed_Row_Odd {
        background: white;
    }
    .cColum_Fixed_Row_Even {
        background: lightgray;
    }
    
    .cRow0 td:nth-child(35n + 2),
    .cRow0 td:nth-child(35n + 3) {
        background-color: red;
    }
    .cRow0 td:nth-child(35n + 4),
    .cRow0 td:nth-child(35n + 5) {
        background-color: cyan;
    }
    .cRow0 td:nth-child(35n + 6),
    .cRow0 td:nth-child(35n + 7),
    .cRow0 td:nth-child(35n + 8),
    .cRow0 td:nth-child(35n + 9),
    .cRow0 td:nth-child(35n + 10) {
        background-color: lime;
    }
    .cRow0 td:nth-child(35n + 11),
    .cRow0 td:nth-child(35n + 12),
    .cRow0 td:nth-child(35n + 13) {
        background-color: red;
    }
    
    .cRow0 td:nth-child(35n + 14),
    .cRow0 td:nth-child(35n + 15),
    .cRow0 td:nth-child(35n + 16),
    .cRow0 td:nth-child(35n + 17),
    .cRow0 td:nth-child(35n + 18),
    .cRow0 td:nth-child(35n + 19) {
        background-color: lime;
    }
    
    .cRow0 td:nth-child(35n + 20),
    .cRow0 td:nth-child(35n + 21),
    .cRow0 td:nth-child(35n + 22) {
        background-color: cyan;
    }
    
    .cRow0 td:nth-child(35n + 23),
    .cRow0 td:nth-child(35n + 24),
    .cRow0 td:nth-child(35n + 25),
    .cRow0 td:nth-child(35n + 26),
    .cRow0 td:nth-child(35n + 27) {
        background-color: lime;
    }
    
    .cRow0 td:nth-child(35n + 28),
    .cRow0 td:nth-child(35n + 29) {
        background-color: red;
    }
    .cRow0 td:nth-child(35n + 30),
    .cRow0 td:nth-child(35n + 31) {
        background-color: cyan;
    }
    
    .cRow0 td:nth-child(35n + 32),
    .cRow0 td:nth-child(35n + 33),
    .cRow0 td:nth-child(35n + 34),
    .cRow0 td:nth-child(35n + 35),
    .cRow0 td:nth-child(35n + 36) {
        background-color: lime;
    }
    <div id="idDiv_Main" class="cDiv_Main">
        <div id="idDiv_Title" class="cDiv_Title">INFINITE HORIZONTAL SCROLLING</div>
        <div id="idDiv_Table" class="cDiv_Table">
            <table id="idTable_Main" class="cTable_Main">
                <tbody>
                    <tr id="idRow0">
                        <td class="cColum_Fixed_Row_Odd">ROW 0</td>
                    </tr>
                    <tr id="idRow1">
                        <td class="cColum_Fixed_Row_Even">ROW 1</td>
                    </tr>
                    <tr id="idRow2">
                        <td class="cColum_Fixed_Row_Odd">ROW 2</td>
                    </tr>
                    <tr id="idRow3">
                        <td class="cColum_Fixed_Row_Even">ROW 3</td>
                    </tr>
                    <tr id="idRow4">
                        <td class="cColum_Fixed_Row_Odd">ROW 4</td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>

How to add symbols or characters between each react element?

I am designing a reusable component for breadcrumbs and I am using compound components pattern. I need to insert symbols between each breadcrumb name like how we would do for array elements and use join method but I am not sure how to do that with react elements.

import React from "react";

const BreadcrumbsItem = ({ children }) => (
  <p>
    {children}
  </p>
);

const Breadcrumbs = ({ children }) => <FlexContainer>{children}</FlexContainer>;

Breadcrumbs.Item = BreadcrumbsItem;

export default Breadcrumbs;

Input:

<Breadcrumbs>
  <Breadcrumbs.Item>Home</Breadcrumbs.Item>
  <Breadcrumbs.Item>Library</Breadcrumbs.Item>
  <Breadcrumbs.Item>Data</Breadcrumbs.Item>
</Breadcrumbs>

Output:

enter image description here

How to export functions in a another function?

To serve my app as a microfrontend with qiankun, I need to export these three functions in main.ts file.

export async function bootstrap () {
  // ...
}

export async function mount (props) {
  // ...
}

export async function unmount () {
  // ...
}

What I am trying to achieve is, how can I export these functions in another function?

serveMicroApp({
  onMount: (props) => { /** */ },
  onBootstrap: () => { /** */ }
  onUnmount: () => { /** */ }
})

So, how should be the content of serveMicroApp function to achieve the same thing as above (first code block)?