Two way data binding in angular 12

I’ve been using angular for a while. I want to implement two way binding but I’m stuck with the following code.

Since [(ngModel)] is no no longer used in angular 12 within the formGroup I’m unable to find a solution

socials = [
{ name: 'Facebook', icon: 'facebook.webp', selected: false, link:'' },
{ name: 'Instagram', icon: 'instagram.webp', selected: false, link:'' },
{ name: 'Twitter', icon: 'linkdin.webp', selected: false, link:'' },
{ name: 'Whatsapp', icon: 'whatsapp.webp', selected: false, link:'' }

];

here I want to change the value of link that will be entered in the following input (6th last line)

<div class="row">
        <div class="col-6 col-lg-3 my-2" *ngFor="let control of socialsArray.controls; let i = index;">
          <input class="form-check-input" type="checkbox" (change)="getSelectedSocialsCards()" [formControl]="control" id="checkbox{{i}}">
          <label for="checkbox{{i}}" class="w-100">
            <div class="card cursorIn" [ngStyle] = "{'background-color' : socials[i].selected == true ? '#ededed' : '#fff'}">
              <div class="d-flex justify-content-end pt-2 pr-2 h-25">
                <fa-icon [icon]="faCheckCircle" [ngClass]="socials[i].selected === true ? 'iconColor' : 'iconColor1'"></fa-icon>
              </div>
              <div class="card-body d-flex p-0 px-4 mt-0">
                <div class="col-3 align-self-center font-weight-bold text-center cardIcon p-0">
                  <img src="/assets/images/social_media/{{socials[i].icon}}" width="40px" height="40px"
                    class="rounded-circle">
                </div>
                <div class="col-9 d-flex flex-column justify-content-start align-items-start cardRight">
                  <div>
                    {{socials[i].name}}
                  </div>
                </div>
              </div>
            </div>
            <div class="col-12 mt-2" [ngStyle] = "{'display' : socials[i].selected == true ? 'block' : 'none' }">
              <div class="form-group">
                <label>
                  {{socials[i].name}} link
                </label>
                <input type="text" class="form-control" (change)="getSelectedSocialsCards()" formControlName="socialLink">
              </div>
            </div>
          </label>
        </div>
      </div>

I’ve declared socialLink inside formGroup

socialLink:new FormControl(null, [Validators.required])

this is my component.ts code for the same

getSelectedSocialsCards() {
this.selectedSocialsCards = [];
this.socialsArray.controls.forEach((control, i) => {
  this.socials[i].selected = false;
  if (control.value) {
    this.socials[i].selected = true;
    this.socials[i].link = this.addForm.get('socialLink').value;
   let linksValue = {'socialName': this.socials[i].name, 'socialLink': this.socials[i].link}
    this.selectedSocialsCards.push(linksValue);
  }
});
console.log(this.selectedSocialsCards);
this.socialError =  this.selectedSocialsCards.length > 0 ? false : true;
this.addForm.patchValue({socialsCheck: this.selectedSocialsCards});

}

So far I’m able to get the last value inserted intot he input field and that is the value of all the links.

I’ve tried to resolve the issue but couldn’t find any solution. I’ll be obliged if anyone can help me with this.
Thank you

Is there a way to get aspect ratio of the webcam in firefox

I’m trying to get the aspect ratio of the webcam using javascript.
As per this documentation, it’s not working for firefox.
https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackSettings/aspectRatio

As Per it says, and I tried it’s working in chrome perfectly well and not working in firefox, it gives undefined for aspect ratio in firefox.

But I have seen that this site – https://webcamtests.com/
Somehow able to detect the aspect ratio of the webcam?

Is there any workaround to get the aspect ratio for firefox?

jQuery and extending built-in elements

I am just looking into extending built-in elements for the first time and have some basic questions.

Let’s say I want to extend a p element, assign it a class, and make it contenteditable. Is the following correct and ready-to-use?

      customElements.define('p-edit', pedit, { extends: 'p' });

      class pedit extends HTMLParagraphElement {
        constructor() {
            
            super();
          
            this.classList.add("foo");
            this.setAttribute("contenteditable",true);
        
        }
    }
      

And would that pedit element be a valid jQuery selector? And would it be a match if the jQuery selector were 'p[contenteditable="true"]' ?

How do I make a call to an API in Rails? I know the information I’m trying to pull and have the link, I just need to know where it goes

I am building a sample app in Rails and trying to use the API sportmonks. I have installed their gemfile and configured my API token in config/environments.

Rails.application.configure do
  
  Sportmonks.configure do |config|
  config.api_token = "PzyBgl38lvSgBL5D3mwQbKQ2HfXABJLxmxyrBdzQ1Gt90dSoJ3Jjg3dWRqIN"
end
end

Now, I need to be able to figure out how to use a call link to get JSON, or how to access that. I have been looking for information on this for 2 days and haven’t found anything that points me to the next step.

I would like to be able to use that API data to customize a sports webpage displaying scores and player data, but first I just need to find out how to actually make the request from my app and where everything goes.

The link I’m trying to use as a small sample is to pull the basic data from one league, using the link supplied by the site

https://soccer.sportmonks.com/api/v2.0/leagues/501?api_token=MYTOKENHERE=season,

So, where does that link go? I know it calls to the API and returns a JSON that looks like this

{
    "data": {
        "id": 501,
        "active": true,
        "type": "domestic",
        "legacy_id": 66,
        "country_id": 1161,
        "logo_path": "https://cdn.sportmonks.com/images/soccer/leagues/501.png",
        "name": "Premiership",
        "is_cup": false,
        "is_friendly": false,
        "current_season_id": 18369,
        "current_round_id": 247456,
        "current_stage_id": 77453684,
        "live_standings": true,
        "coverage": {
            "predictions": true,
            "topscorer_goals": true,
            "topscorer_assists": true,
            "topscorer_cards": true
        },
        "season": {
            "data": {
                "id": 18369,
                "name": "2021/2022",
                "league_id": 501,
                "is_current_season": true,
                "current_round_id": 247456,
                "current_stage_id": 77453684
            }
        }
    },
    "meta": {
        "plans": [
            {
                "name": "Football Free Plan",
                "features": "Standard",
                "request_limit": "180,60",
                "sport": "Soccer"
            }
        ],
        "sports": [
            {
                "id": 1,
                "name": "Soccer",
                "current": true
            }
        ]
    }
}

But I have zero idea of where that would show up on my Rails app, or how to make that request from it.

Any kind of help would be appreciated.

Wanted to Remove duplicate values from an array of objects in react for select components

I wanted to remove data from my array of objects, There are a lots of duplicate values in my data.

Array of Objects:

rawData = [
0: {
  style_no: "BAG-011459",
  Item_description: "Hoplite Top Load Bag Standard 21 x 36 Olive",
  mon: "21310026-4",
  type: "Bags",
  oq: 51,
  force_update: 62,
  c_n: "WHITE DUCK",
  pl_q: 51,
  os: "Open",
},
1: {
  style_no: "BAG-010865",
  Item_description: "Hoplite Top Load Bag Large 25 x 42  Olive",
  mon: "21310030-5",
  type: "Bags",
  oq: 102,
  force_update: 63,
  c_n: "WHITE DUCK",
  pl_q: 102,
  os: "Open",
},
2: {
  style_no: "BAG-011932",
  Item_description: "Hoplite Top Load Bag Large 25x42 Black",
  mon: "21310035-8",
  type: "Bags",
  oq: 464,
  force_update: 64,
  c_n: "WHITE DUCK",
  pl_q: 464,
  os: "Open",
},
3:{
  style_no: "BAG-011932",
  Item_description: "Hoplite Top Load Bag Large 25x42 Black",
  mon: "21310034-8",
  type: "Bags",
  oq: 464,
  force_update: 65,
  c_n: "WHITE DUCK",
  pl_q: 464,
  os: "Open",
},
4:{
  style_no: "BAG-011931",
  Item_description: "Hoplite Top Load Bag Standard 21x36 Black",
  mon: "21310034-7",
  type: "Bags",
  oq: 160,
  force_update: 66,
  c_n: "WHITE DUCK",
  pl_q: 160,
  os: "Open",
},
5: {
  style_no: "BAG-011931",
  Item_description: "Hoplite Top Load Bag Standard 21x36 Black",
  mon: "21310036-7",
  type: "Bags",
  oq: 150,
  force_update: 67,
  c_n: "WHITE DUCK",
  pl_q: 150,
  os: "Open",
},
6: {
  style_no: "BAG-011931",
  Item_description: "Hoplite Top Load Bag Standard 21x36 Black",
  mon: "21310035-7",
  type: "Bags",
  oq: 160,
  force_update: 68,
  c_n: "WHITE DUCK",
  pl_q: 160,
  os: "Open",
},
7: {
  style_no: "BAG-011460",
  Item_description: "Hoplite Top Load Bag Extra Large 30 x 50 Olive",
  mon: "21310034-6",
  type: "Bags",
  oq: 456,
  force_update: 69,
  c_n: "WHITE DUCK",
  pl_q: 456,
  os: "Open",
},
8: {
  style_no: "BAG-011460",
  Item_description: "Hoplite Top Load Bag Extra Large 30 x 50 Olive",
  mon: "21310035-6",
  type: "Bags",
  oq: 456,
  force_update: 70,
  c_n: "WHITE DUCK",
  pl_q: 456,
  os: "Open",
},
]

Select Body:

    {/* Customer */}
    <FormControl sx={{ m: 0.5 }} variant="standard">
      <InputLabel
        style={{ fontSize: "15px" }}
        id="demo-customized-select-label"
      >
        Customer
      </InputLabel>
      <Select
        required
        style={{
          fontSize: "12px",
          width: "125px",
        }}
        labelId="demo-customized-select-label"
        id="demo-customized-select"
        value={plandata.customer}
        onChange={(e) => {
          setPlanData((prev) => ({ ...prev, customer: e.target.value }));
        }}
        input={<BootstrapInput />}
      >
        {rawData
          ?.filter((data) => data.type.includes(plandata.division))
          .map((value) => (
            <MenuItem value={value.c_n.toString()}>
              {value.c_n.toString()}
            </MenuItem>
          ))}
      </Select>
    </FormControl>

The snippest of the select box is

Select Button for cusomer

Please if you know how to do it please answer this query, I am stuck on this project form last 2 months, wanted to do it asap, with your support thanks.

Note: I already go through the answers which was related to this question but not find my query.

Moving to next form field when full Plotly-Dash Python App

I’m trying to move the focus to the next input field when they reach their max length.
(I’ve heard this called ‘autotabbing’ elsewhere on various stackoverflow pages.)

I’m using dash-bootstrap-components (dbc), but I assume that will not really change the answer vs dcc

The input fields are generated with:

import dash
from dash import dcc, html, dash_table, Input, Output, State, MATCH, ALL
import dash_bootstrap_components as dbc
from app.data_operations import *

app = dash.Dash()

app.layout = html.Div(

    dbc.Row(
        children=[
            dbc.Col(dbc.Input(id={'identifier': 'form', 'element_id': i}, placeholder='A',
                              type='text', size="lg", maxlength=1, value='')) for i in range(5)
        ],
        justify='between',
    ),
)

So far I’ve tried:

  • adding some random js scripts I found on the internet
  • a fruitless attempt at using a jQuery package before reading that jQuery doesn’t play nicely with Dash’s React.

Is there a Dash / Python solution here?

Or some kind of external script I can add here?

(I’m a real javascript novice, so don’t really know how I’d go about writing the functions for that)

How to print numeric object attributes using console?

I am a beginner in the middle of a js basics course. I have a simple object related exercise and everything seems to be working except for the numeral values where the console prints the function instead of the wanted result.

// My code -->
const pete = {

  firstname1: "Pete",
  fullname1: "Pete Programmer",
  age: 20,
  
        firstname: function() {return this.firstname1},
        fullname: function() {return this.fullname1},
        age1: function() {return this.age1}
}       
const cara = {
    firstname1: "Cara",
    fullname1: "Cara Code",
  age1: 32,
        firstname: function() {return this.firstname1},
        fullname: function() {return this.fullname1},
        age: function() {return this.age1}
}
// teachers uneditable code -->

console.log("Name: " + pete.fullname() + "tAge: " + pete.age);
console.log("Name: " + cara.fullname() + "tAge: " + cara.age);

console.log(cara.firstname + "is " + (cara.age - pete.age) + " years older than " + pete.firstname);

Console output:

"Name: Pete Programmer  Age: 20"
"Name: Cara Code    Age: function() {return this.age1}"
"function() {return this.firstname1}is NaN years older than function() {return this.firstname1}"

I havent been able to find the answer despite this looking like a simple problem.

Angular Button list, overflow in to list instead of wrap

I have a list of buttons:
enter image description here

when there is overflow, I want the buttons to be in a drop list
like this:

enter image description here

And i need it to be dynamic (re arrange page size change)

I tryed this:

 ngAfterViewInit() {
    const width = this.container.nativeElement.offsetWidth;
    const fittingActions = [...this.container.nativeElement.children];
    let fittingActionsWidth = 0;

    for (const action of fittingActions) {
      fittingActionsWidth = fittingActionsWidth + action.clientWidth
      if (fittingActionsWidth < width) {
        this.actionCountToDisplay = this.actionCountToDisplay + 1
      }
    }
  }
<ng-container *ngFor="let action of actionButtons.slice(0, actionCountToDisplay || actionButtons.length)">
    <button
      (click)="action.onClick($event)"
      mat-flat-button color="primary">
      <span>{{action.label}}</span>
    </button>
  </ng-container>

but it dident work wel

How to adjust space between SVG over an SVG path using CSS?

I made a rookie DIY design for a saree. I used the SVG’s to place over another SVG for it. Which works fine, but need to be able to adjust the distance between replicated SVG’s (both vertical and horizontal).

Here’s how it looks now:

enter image description here

In the above picture, I was able to add an SVG(design) over another plain SVG(saree) and the replicates. But how do I manipulate the distance between them using CSS.

Here’s the code in JSFiddle:

<style>
.blowse-top-detailed {
    width: 500px;
    height: 300px;
    left: 40%;
    top: 5%;
    position: absolute;
}
</style>

<svg class="saree-top saree" xmlns="http://www.w3.org/2000/svg" version="1.0" viewBox="0 0 243.000000 439.000000" preserveAspectRatio="xMidYMid meet">
  <g transform="translate(0.000000,439.000000) scale(0.100000,-0.100000)" fill="#000000" stroke="none">
    <pattern id="saree_pattern_img" patternUnits="userSpaceOnUse" width="100%" height="100%">
      <svg id="saree_img" xmlns="http://www.w3.org/2000/svg" width="200px" height="200px" viewBox="0 0 401.000000 254.000000" style="width: 30px;height: 30px;">
        <g xmlns="http://www.w3.org/2000/svg" transform="translate(0.000000,254.000000) scale(0.100000,-0.100000)" fill="#000000" stroke="none">
          <path d="M2865 2381 c-44 -10 -90 -23 -102 -29 -49 -27 -55 -80 -18 -160 37 -80 34 -113 -17 -166 -30 -30 -62 -50 -106 -66 -54 -20 -61 -25 -45 -34 26 -15 132 -10 176 8 20 9 62 39 92 66 40 36 69 53 112 65 90 25 121 42 139 76 20 40 16 62 -35 172 l-41 87 -37 -1 c-21 -1 -74 -9 -118 -18z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M992 2351 c-18 -11 -52 -133 -52 -183 0 -49 44 -100 102 -117 24 -8 57 -18 75 -23 18 -5 66 -36 107 -69 83 -66 118 -81 156 -67 l25 10 -25 10 c-93 37 -117 59 -127 121 -4 27 2 51 27 101 l32 66 -25 54 c-31 67 -56 81 -162 89 -44 3 -89 9 -100 12 -11 3 -26 1 -33 -4z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M3175 2136 c-35 -15 -90 -74 -112 -121 -15 -30 -14 -37 1 -75 l16 -42 -28 -26 c-49 -46 -135 -82 -246 -104 -58 -12 -106 -25 -106 -29 0 -15 150 -10 220 6 36 9 106 32 155 53 85 35 96 37 207 38 110 1 120 3 158 28 53 35 67 64 52 113 -6 21 -14 64 -18 96 -4 32 -10 60 -14 62 -5 3 -64 7 -132 10 -88 3 -132 0 -153 -9z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M557 2123 c-4 -3 -7 -14 -7 -23 0 -9 -11 -38 -25 -64 -14 -26 -25 -58 -25 -71 0 -31 43 -81 93 -107 36 -18 51 -19 141 -13 90 6 106 4 151 -15 28 -12 91 -33 140 -46 155 -43 432 -42 438 1 1 6 -52 12 -133 16 -142 6 -206 22 -314 76 -80 40 -88 50 -80 101 6 41 4 46 -32 84 -57 59 -85 68 -222 68 -65 0 -122 -3 -125 -7z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M1933 2102 c-56 -31 -78 -69 -78 -139 0 -72 19 -105 81 -140 72 -42 153 -22 205 50 54 74 33 180 -43 227 -41 25 -121 26 -165 2z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M1017 1974 c-8 -8 2 -35 22 -58 31 -36 205 -96 242 -84 13 4 -114 105 -169 134 -27 14 -84 19 -95 8z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M2930 1949 c-14 -6 -41 -25 -60 -44 -20 -19 -65 -46 -100 -61 -84 -34 -94 -44 -43 -44 47 0 220 54 246 77 10 9 17 30 17 50 0 36 -13 41 -60 22z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M1734 1876 l-39 -33 20 -38 c28 -52 90 -112 150 -143 44 -24 61 -27 150 -27 89 0 105 3 151 27 51 27 127 102 147 146 9 20 5 28 -28 62 -22 22 -46 40 -55 40 -8 0 -26 -20 -39 -44 -13 -25 -40 -57 -61 -71 -102 -71 -216 -46 -296 65 -20 27 -41 50 -48 50 -7 0 -30 -15 -52 -34z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M3524 1811 c-26 -12 -57 -40 -85 -77 -25 -33 -64 -69 -86 -82 -121 -67 -410 -70 -627 -6 -105 30 -50 -12 65 -50 85 -29 186 -41 404 -52 l149 -7 46 -47 c39 -40 55 -50 104 -60 32 -7 96 -10 141 -8 77 3 86 5 122 36 21 18 66 54 100 80 40 30 62 54 63 68 0 32 -175 199 -225 213 -59 16 -124 13 -171 -8z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M1611 1784 c-27 -34 -27 -41 7 -95 54 -83 156 -160 255 -191 104 -32 246 -19 355 34 90 43 221 192 206 233 -4 8 -15 20 -25 25 -37 20 -58 11 -99 -45 -48 -65 -113 -115 -182 -140 -73 -26 -195 -18 -268 19 -59 29 -138 101 -171 154 -25 39 -51 41 -78 6z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M365 1768 c-11 -7 -64 -45 -117 -85 -119 -90 -123 -103 -47 -163 29 -22 64 -58 80 -79 34 -47 96 -71 186 -71 97 0 152 28 198 101 l23 36 134 7 c206 11 392 46 516 97 84 35 59 55 -29 23 -256 -90 -590 -60 -656 61 -33 61 -87 85 -187 85 -45 0 -90 -6 -101 -12z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M782 1768 c-19 -19 -15 -32 23 -71 32 -33 40 -36 93 -36 31 0 118 -3 192 -6 112 -5 147 -3 204 12 87 23 104 48 24 36 -83 -12 -258 -9 -315 5 -33 9 -60 24 -77 43 -23 25 -33 29 -79 29 -29 0 -58 -5 -65 -12z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M3150 1736 c-41 -22 -62 -24 -239 -29 -106 -3 -195 -8 -198 -11 -6 -6 1 -9 62 -26 47 -13 396 -26 447 -16 35 6 88 46 88 65 0 9 -83 41 -104 41 -6 -1 -31 -11 -56 -24z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M1470 1730 c-24 -24 -24 -29 -4 -58 22 -31 69 -30 90 3 15 23 15 27 0 50 -20 31 -58 33 -86 5z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M2482 1729 c-30 -11 -39 -54 -17 -79 25 -28 61 -25 81 5 30 47 -10 94 -64 74z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M1532 1610 c-16 -27 -15 -41 7 -67 24 -29 42 -29 69 0 28 29 28 41 0 67 -28 25 -60 26 -76 0z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M2400 1591 c-16 -31 -12 -49 15 -67 21 -14 31 -15 50 -6 24 11 30 27 25 62 -5 34 -73 42 -90 11z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M2647 1581 c35 -29 166 -80 270 -106 51 -13 113 -31 137 -40 49 -19 99 -15 132 10 19 15 19 15 0 30 -20 15 -53 22 -257 54 -75 12 -169 32 -209 46 -87 30 -103 31 -73 6z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M1325 1535 c-149 -55 -227 -71 -276 -56 -38 11 -45 10 -96 -15 -47 -23 -53 -28 -41 -41 35 -34 82 -28 277 36 103 35 206 73 227 86 55 34 20 30 -91 -10z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M1639 1521 c-20 -16 -22 -23 -14 -47 6 -18 21 -33 39 -39 24 -8 31 -6 47 14 22 27 24 41 7 63 -21 27 -53 30 -79 9z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M2580 1525 c26 -31 190 -131 307 -187 68 -32 127 -67 133 -78 5 -10 10 -34 10 -53 0 -42 41 -87 115 -124 l49 -26 121 18 c66 10 127 21 135 26 9 4 20 36 28 76 7 37 15 80 19 95 11 56 -3 78 -75 111 -86 39 -154 42 -232 8 -44 -19 -65 -22 -110 -18 -87 10 -293 73 -396 122 -99 48 -125 55 -104 30z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M2306 1509 c-31 -25 -33 -49 -5 -74 19 -19 21 -19 55 0 37 20 42 39 18 73 -19 27 -34 28 -68 1z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M1403 1465 c-87 -40 -264 -93 -354 -106 -80 -12 -91 -11 -165 10 l-79 23 -65 -22 c-107 -36 -126 -52 -170 -145 -42 -88 -49 -125 -27 -144 16 -13 123 -31 223 -38 64 -5 76 -2 130 25 71 36 79 44 93 97 6 22 16 49 24 58 7 10 111 69 232 131 120 62 221 118 223 125 5 16 -7 14 -65 -14z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M1762 1437 c-29 -30 -28 -53 3 -73 48 -31 98 12 73 64 -17 35 -48 39 -76 9z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M2181 1436 c-28 -30 -24 -57 12 -74 24 -12 31 -11 53 2 31 21 30 37 -2 70 -33 32 -35 32 -63 2z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M2486 1429 c3 -6 61 -47 128 -90 66 -44 135 -96 152 -116 30 -34 35 -36 95 -37 58 -1 64 1 67 20 5 35 -57 81 -120 89 -52 7 -124 41 -235 112 -50 32 -102 45 -87 22z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M1896 1414 c-33 -32 -10 -94 35 -94 23 0 59 34 59 55 0 21 -36 55 -59 55 -11 0 -27 -7 -35 -16z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M2036 1404 c-21 -21 -20 -47 2 -67 23 -21 56 -22 76 -1 32 32 8 84 -39 84 -13 0 -31 -7 -39 -16z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M1462 1360 c-66 -35 -100 -46 -240 -80 -49 -13 -82 -41 -82 -70 0 -18 7 -20 60 -20 37 0 74 7 93 17 58 30 267 173 267 183 0 16 -21 10 -98 -30z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M2350 1357 c0 -16 53 -64 212 -190 54 -43 105 -89 114 -103 9 -13 20 -58 24 -98 7 -76 22 -107 73 -154 19 -18 56 -30 147 -48 68 -14 137 -24 154 -22 28 3 31 7 33 38 2 19 8 65 14 101 14 82 8 109 -37 158 -52 58 -112 82 -226 91 -92 7 -103 11 -200 62 -90 48 -213 119 -285 166 -20 13 -23 12 -23 -1z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M1518 1277 c-193 -126 -227 -142 -312 -139 -84 2 -146 -23 -213 -87 -48 -46 -56 -79 -51 -201 l3 -75 99 -9 c121 -10 158 0 217 58 51 50 58 69 52 129 -9 76 7 98 171 234 149 124 176 149 176 165 0 15 -16 7 -142 -75z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M2276 1321 c-9 -13 56 -139 102 -199 18 -24 47 -70 64 -102 33 -63 67 -87 129 -92 l34 -3 -2 48 c-2 56 -25 97 -54 97 -35 0 -53 16 -144 122 -124 144 -122 142 -129 129z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M1664 1221 c-48 -46 -109 -92 -150 -113 -76 -40 -97 -59 -113 -100 -21 -57 12 -73 88 -42 24 10 51 32 72 62 19 26 69 91 112 145 43 54 77 104 75 112 -2 8 -36 -19 -84 -64z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M2180 1281 c0 -30 46 -152 112 -296 72 -155 78 -186 49 -243 -28 -55 -26 -98 7 -162 40 -79 64 -93 180 -101 53 -4 116 -11 138 -14 23 -4 44 -3 47 1 3 5 12 61 22 125 15 103 15 120 2 150 -41 94 -112 149 -194 149 -41 0 -58 5 -83 27 -38 31 -160 202 -222 308 -44 76 -58 90 -58 56z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M1986 1208 c-3 -29 -8 -120 -11 -203 -7 -166 -21 -299 -36 -328 -9 -15 -18 -17 -67 -11 -49 5 -61 3 -85 -16 -36 -28 -60 -78 -82 -167 -17 -71 -17 -73 4 -116 17 -34 33 -50 77 -73 59 -31 108 -73 162 -142 18 -23 41 -42 50 -42 10 0 40 17 68 38 27 20 89 66 137 101 67 49 89 72 96 97 17 63 -9 198 -50 256 -19 26 -68 49 -99 46 -32 -3 -48 3 -54 17 -7 18 -72 444 -81 533 -4 34 -11 62 -15 62 -5 0 -11 -24 -14 -52z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M1755 1144 c-164 -224 -207 -264 -281 -264 -26 0 -53 -8 -75 -23 -44 -30 -106 -112 -113 -151 -5 -32 25 -231 38 -243 4 -4 60 -6 124 -4 134 3 135 4 203 105 45 67 49 101 19 176 -11 28 -20 61 -20 73 0 12 43 108 96 213 53 105 94 199 93 209 -3 13 -28 -15 -84 -91z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M1904 1239 c-6 -8 -25 -57 -43 -109 -34 -96 -79 -194 -112 -242 -35 -48 -20 -158 21 -158 29 0 77 27 90 49 5 11 10 52 10 92 0 40 12 132 26 205 26 137 29 190 8 163z" style="fill: rgb(255, 255, 255);"></path>
          <path d="M2094 1233 c3 -10 15 -70 27 -133 23 -124 27 -204 15 -261 -8 -34 -5 -40 34 -83 23 -25 48 -46 56 -46 13 0 74 98 74 118 0 6 -11 21 -24 34 -16 14 -46 79 -80 171 -31 82 -63 164 -72 183 -17 35 -39 48 -30 17z" style="fill: rgb(255, 255, 255);"></path>
        </g>
      </svg>
    </pattern>
  </g>
</svg>
<svg class="saree-top-detailed saree detailed_indi" xmlns="http://www.w3.org/2000/svg" version="1.0" viewBox="0 0 121.000000 95.000000" preserveAspectRatio="xMidYMid meet" style="display: block;">
  <g transform="translate(0.000000,95.000000) scale(0.100000,-0.100000)" fill="#000000" stroke="none">
    <rect class="path_saree" x="10" y="10" width="1200px" height="500px" fill="black" stroke="black" style="fill: rgb(25, 36, 112);"></rect>
    <rect class="path_saree_img" x="10" y="10" width="1200px" height="500px" fill="black" stroke="black" style="display: block; fill: url(&quot;#saree_pattern_img&quot;);"></rect>
  </g>
</svg>

Any help is greatly appreciated.

Javascript: I can’t find how to get the coordinates of a mouseClick relative to the ENTIRE viewable document

I need a way to find the coordinates of a mouseclick relative to the entire document. I am aware of pageX and pageY, but these values do not take in account the true entire document, or rather what I really mean is, these values do not consider the currently viewable document, AND the left over scrollable document. So while the X value is fine because this page does not scroll on the X-axis, it means that the Y value will change depending on WHERE the user is on account of the ability to scroll.

I feel like I must be missing something obvious?

Overflow-y: scroll; on side navigation prevents tooltip functionality

I have a side navigation with the following styles

position: fixed;
left: 0;
top: 0;
height: 100%;
width: 78px;
background: #11101D;
padding: 6px 14px;
z-index: 99;
transition: all 0.5s ease;
overflow-x: visible;
overflow-y: scroll;

Which allows the user to scroll vertically on the side navigation.

When a user hovers on a navigation item, a tooltip appears to the right.

position: absolute;
top: -20px;
left: calc(100% + 15px);
z-index: 3;
background: #fff;
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.3);
padding: 6px 12px;
border-radius: 4px;
font-size: 15px;
font-weight: 400;
opacity: 0;
white-space: nowrap;
pointer-events: none;
transition: 0s;

However, because of the overflow-y: scroll; on the parent, it doesn’t overlap the sidebar, instead you scroll horizontally to see it, which isn’t desired.

Current Tooltip

on hover
on hover and vertical scroll

Desired Tooltip (with side nav scroll functionality)

tooltip visible with scroll

I have a JSFiddle with all the markup and styles.

I want the the side nav to be vertically scrollable while still having the functionality to view the tooltip.

Any help would be greatly appreciated. This is based on a React Application, so would prefer non JQuery solutions.

Why don’t these error properties show under keys?

It seems from Object.getOwnPropertyNames vs Object.keys, that the main difference between Object.keys() and Object.getOwnPropertyNames() is that the former only returns some of the properties — those that are enumerable. So I’m wondering for something like an Error object, why it’s decided that the properties aren’t enumerable. For example:

try {
    let field="XYZ";
    field.a.b.c;
} catch (error) {
    console.log('111', Object.getOwnPropertyNames(error));
    console.log('222', Object.keys(error));
}

Why for example does the Error object not make those properties enumerable? When is a property usually made enumerable?

cleaner way to check whether or not a the current window.location.href is equal to any of the strings in the array

Im trying to do a redirect if the url is equal to any of the strings in the following array of urls:

So I did the following

function redirectUser() {
  if (window.location.href === 'https://swish.com/login' || window.location.href === 'https://swish.com/register' || window.location.href === 'https://swish.com/overview') {
    window.location.replace('https://swish.com/onboard');
  }
}

But this is a bit ugly, so I thought of putting the urls in an array and doing something like this:

function redirectUser() {
  const urls = ['https://swish.com/login', 'https://swish.com/register', 'https://swish.com/overview' ]
for(let url of urls) {
  if (window.location.href === url) {
    window.location.replace('https://swish.com/onboard');
  }
 }
}

Is there any other way to do this? If not, which would be the better option in your opinion? Thanks!

Unable to transform control code for a Top Down RPG player into React Hook

First please excuse me for this long post. I tried to make it the smaller I can but everything come together so I cannot make it smaller than that.

The need

I want to create a Top Down RPG online (like Pokemon), and I like React so I did choose it as Framework.
I tried one time, didn’t work.. So I tried another, and something like 6 different solution but impossible..

So I did a vanilla JS version of it

A working JS vanilla version

// ----- Const -----

const DIRECTION = {
  UP: 'up',
  DOWN: 'down',
  LEFT: 'left',
  RIGHT: 'right',
};

const FPS = 5;
const MOVE_TIME = 1000/FPS;   //
const MOVE_DISTANCE = 64/FPS; //  64px/sec

// ----- Variable -----

let isWalking = false;
let direction = DIRECTION.DOWN;
let position = {x:64, y:32};


let isDirectionPressed = {}; // [DIRECTION]: bool
let timerId = null;
let delayId = null;
let lastMoveTime = 0;

// ----- Refresh HTML -----

const updatePlayer = () => {
  player.style.top = `${position.y}px`;
  player.style.left = `${position.x}px`;
  player.className = `${direction} ${isWalking ? 'walk' : ''}`;
}

// --------------- Engine ---------------

// Init
updatePlayer();

// Start moving in a direction
const go = (dir) => {
  // If we already know that, avoid
  if (!dir || isDirectionPressed[dir] && isWalking) {
    return;
  }

  isDirectionPressed[dir] = true;
  direction = dir;
  isWalking = true;
  clearTimers();

  // Do we start now ? Or wait (because we already move/stop during the delay - Low FPS)
  let now = new Date().getTime();
  let delay = Math.max(0, (lastMoveTime + MOVE_TIME) - now);
  delayId = setTimeout(() => {
    if (isWalking) { // Are we still walking after delay ?
      move();
      timerId = setInterval(() => {
        move();
      }, MOVE_TIME);
    }
  }, delay);

  updatePlayer();
}

// Do the move here
const move = () => {
  lastMoveTime = new Date().getTime();

  if (direction == DIRECTION.UP) {
    position.y -= MOVE_DISTANCE;
  }
  if (direction == DIRECTION.DOWN) {
    position.y += MOVE_DISTANCE;
  }
  if (direction == DIRECTION.LEFT) {
    position.x -= MOVE_DISTANCE;
  }
  if (direction == DIRECTION.RIGHT) {
    position.x += MOVE_DISTANCE;
  }

  updatePlayer();
}

// Clear 
const clearTimers = () => {
  clearInterval(timerId);
  timerId = null;
  clearTimeout(delayId);
  delayId = null;
}


// --------------- Events ---------------

const onKeyDown = (e) => {
  go(keyCodeToDirection(e.keyCode));
};

const onKeyUp = (e) => {
  const dir = keyCodeToDirection(e.keyCode);
  if (!dir) {
    return;
  }
  isDirectionPressed[dir] = false;

  // Stop here (or go in another pressed direction)
  if (dir === direction) {
    if (isDirectionPressed[DIRECTION.UP]) direction = DIRECTION.UP;
    else if (isDirectionPressed[DIRECTION.DOWN]) direction = DIRECTION.DOWN;
    else if (isDirectionPressed[DIRECTION.LEFT]) direction = DIRECTION.LEFT;
    else if (isDirectionPressed[DIRECTION.RIGHT]) direction = DIRECTION.RIGHT;
    else {
      isWalking = false; // Stop
      clearTimers();
      updatePlayer();
    }
  }
};

window.addEventListener('keyup', onKeyUp);
window.addEventListener('keydown', onKeyDown);

const keyCodeToDirection = (keyCode) => {
  if (keyCode === 37) { return DIRECTION.LEFT }
  else if (keyCode === 38) { return DIRECTION.UP }
  else if (keyCode === 39) { return DIRECTION.RIGHT }
  else if (keyCode === 40) { return DIRECTION.DOWN }
}
html, body {
  height: 100%;
  margin: 0;
  padding: 0;
}
body {
  display: flex;
}

#viewport {
  width: 600px;
  height: 150px;
  margin: auto;
  border: 1px solid black;
  position: relative;
}

#player {
  position: absolute;
  background: grey;
  width: 32px;
  height: 32px;
}
#player.up {
  border-top: 3px solid black;
}
#player.down {
  border-bottom: 3px solid black;
}
#player.left {
  border-left: 3px solid black;
}
#player.right {
  border-right: 3px solid black;
}
#player.walk {
  background: orange;
}
    <div id="viewport">
      <div id="player" style="top:32px; left:32px;"></div>
    </div>

N-th times try with React

Now I’m sure I have a working version of this code, and I want to make a useControllable hook who can do the same and return {position, direction, isWalking} state.

Player Component

import React from 'react';

import Character from './character'; 
import useControllable from '../hooks/useControllable';

const Player = () => {
  const { position, direction, isWalking }  = useControllable();

  return <Character position={position} skin={1} direction={direction} isWalking={isWalking} />
};

export default Player;

useControllable Hook

import { useEffect, useState } from "react";

const DIRECTION = {
  UP: 'up',
  DOWN: 'down',
  LEFT: 'left',
  RIGHT: 'right',
};

const FPS = 20;
const MOVE_TIME = 1000/FPS;   //
const MOVE_DISTANCE = 64/FPS; //  64px/sec


export default function useControllable (_position={x:0,y:0}, _direction=DIRECTION.DOWN) {

  // ----- Define States -----

  let [position, setPosition] = useState(_position);
  let [direction, setDirection] = useState(_direction);
  let [isWalking, setWalking] = useState(false);

  // ----- Intern vars -----

  let isDirectionPressed = {}; // [DIRECTION]: bool
  let timerId = null;
  let delayId = null;
  let lastMoveTime = 0;

  // ----- Engine -----

  const go = (dir) => {
    // If we already know that, avoid

    if (!dir || isDirectionPressed[dir] && isWalking) {
      return;
    }

    isDirectionPressed[dir] = true;
    clearTimers();

    setDirection(dir); // direction = dir;
    setWalking(true); // isWalking=true;

    // Do we start now ? Or wait (because we already move/stop during the delay - Low FPS)
    let now = new Date().getTime();
    let delay = Math.max(0, (lastMoveTime + MOVE_TIME) - now);

    // console.log("Start Walking. Delay: " + delay);

    delayId = setTimeout(() => {
      if (isWalking) {
        move();
        timerId = setInterval(() => {
          console.log("Tic");
          move();
        }, MOVE_TIME);
      }
    }, delay);

  }

  const move = () => {

    lastMoveTime = new Date().getTime();

    if (direction === DIRECTION.UP) {
      setPosition({x: position.x, y: position.y - MOVE_DISTANCE});
      // position = {x: position.x, y: position.y - MOVE_DISTANCE};
    }
    else if (direction === DIRECTION.DOWN) {
      setPosition({x: position.x, y: position.y + MOVE_DISTANCE});
      // position = {x: position.x, y: position.y + MOVE_DISTANCE};
    }
    else if (direction === DIRECTION.LEFT) {
      setPosition({x: position.x - MOVE_DISTANCE, y: position.y});
      // position = {x: position.x - MOVE_DISTANCE, y: position.y};
    }
    else if (direction === DIRECTION.RIGHT) {
      setPosition({x: position.x + MOVE_DISTANCE, y: position.y});
      // position = {x: position.x + MOVE_DISTANCE, y: position.y};
    }

  }

  const clearTimers = () => {
    clearInterval(timerId);
    timerId = null;
    clearTimeout(delayId);
    delayId = null;
  }

  // ----- Event Management -----

  const onKeyDown = (e) => {
    go(keyCodeToDirection(e.keyCode));
  };

  const onKeyUp = (e) => {
    const dir = keyCodeToDirection(e.keyCode);
    if (!dir) {
      return;
    }
    isDirectionPressed[dir] = false;

    // Stop here
    if (dir === direction) {
      if (isDirectionPressed[DIRECTION.UP]) setDirection(DIRECTION.UP); // direction = DIRECTION.UP
      else if (isDirectionPressed[DIRECTION.DOWN]) setDirection(DIRECTION.DOWN); // direction = DIRECTION.DOWN
      else if (isDirectionPressed[DIRECTION.LEFT]) setDirection(DIRECTION.LEFT); // direction = DIRECTION.LEFT
      else if (isDirectionPressed[DIRECTION.RIGHT]) setDirection(DIRECTION.RIGHT); // direction = DIRECTION.RIGHT
      else {
        setWalking(false); // isWalking=false;
        clearTimers();
      }
    }
  };

  const keyCodeToDirection = (keyCode) => {
    if (keyCode === 37) { return DIRECTION.LEFT }
    else if (keyCode === 38) { return DIRECTION.UP }
    else if (keyCode === 39) { return DIRECTION.RIGHT }
    else if (keyCode === 40) { return DIRECTION.DOWN }
  }

  useEffect(() => {
    window.addEventListener('keyup', onKeyUp);
    window.addEventListener('keydown', onKeyDown);
    return () => {
      window.removeEventListener('keyup', onKeyUp);
      window.removeEventListener('keydown', onKeyDown);
    };
  }, []);

  return { position, direction, isWalking };
}

But I never works.. When I update a state (like setDirection) the variable direction isn’t updated into the hook, so function always have it as “down” (initial value).
So I tried to update them in the same time (see comment after setter) setDirection(dir); // direction = dir;

Also Timeout and Interval are f*cked here, they fire to much, or not at all.. I tried some version using useEffect() to simulate an Interval (see code under) but it’s always buggy (and the Tic function have to stay on all the time, I cannot stop it. And I’ll have NPC too who can also walk, don’t want one by Character)

  // Tic for animation...

  useEffect(() => {
    const id = setTimeout(() => {
      console.log("Tic " + playerDir, `[${playerPos.x};${playerPos.y}]`);
      setLastMoveTime(new Date().getTime()); // Make it recall later

    }, MOVING_TIME);

    return () => {
      clearTimeout(id);
    }
  }, [lastMoveTime]);

I probably miss something.. Thank all for taking time to read everything.

two functions not calling properly with boolean hooks

I have two functions and I am trying to call them by toggling between classes using react hooks. However, it keeps on throwing an error “TypeError: Cannot read properties of undefined

(reading 'currentTarget')"

and it references this – const element = e.currentTarget;

e.target.value is a string

This is the state

const [color, setColor] = useState(false)

The function to handle the toggle

function addOrRemove(e) {
  const element  = e.currentTarget;
  setColor(!color)
if (color){
  addValue(element)
} else {
  removeValue(element)
}
}

the button that calls the function

<button
                id="btn"
                onClick={addOrRemove()}
                className={color? "red": "white"}/>

the two functions being called

function addValue(e) {
    if (e.target.value !== "") {
      
      if (!favs.includes(e.target.value)) {
        favs.push(e.target.value);
        localStorage.setItem("name", JSON.stringify(favs));
        console.log(favs);
        document.getElementById("favsarray").innerHTML =  favs
      }
    }
  }


function removeValue(e, value) {
    if (e.target.value !== "") {
      //delete from array
      favs.pop(e.target.value);
      console.log(favs);
      //change the div text
      document.getElementById("favsarray").innerHTML = favs;
      //get the values from localstorage- parse
      const stored = JSON.parse(localStorage.getItem("name"));
      //delete the value
      delete stored[(value, e.target.value)];
      //store the new array as a string
      localStorage.setItem("name", JSON.stringify(favs));
      console.log(stored);
    }
  }