Javascript Design Patterns Streaming Service Project

Design for a Music Streaming Service Project

Use the Strategy pattern to handle various music formats, such as Mp3 and Wav.
Implement the Observer pattern to monitor the music playback status.
Define a Subject interface to update the Ui whenever there are any changes.
Apply the Factory pattern to create objects required for music playback. For example, when playing Mp3 format music, create an Mp3 Decoder object, and for Wav format music, create a WavDecoder object.
Utilize the Composite pattern to structure music playlists.
Use the Facade pattern to determine whether the user is a member or not.

I’m not sure if this design I came up with is accurate. I’m a beginner and currently studying, but I don’t know the proper usage of design patterns or the correct order to apply them. Could you show me a simple UML diagram or help me improve the part I designed? Also, please guide me on the appropriate sequence for using design patterns.

If the design I came up with is strange, you can provide a new design as well. Please leave multiple feedback.


I felt like I used multiple patterns, but I had the sense of designing in order to use design patterns, and I’m not sure about the design for the music streaming service.

JSON.stringify Map with nested Set

Consider the following graph:

class Node {
  constructor(value) {
    this.value = value;
    this.adjacents = new Set();
  }

  addAdjacent(node) {
    this.adjacents.add(node);
  }
}

class Graph {
  constructor(directed = false) {
    this.nodes = new Map();
    this.directed = directed;
  }

  addVertex(value) {
    const node = this.nodes.has(value);
    if (node) {
      return this.nodes.get(value);
    }

    const vertex = new Node(value);
    this.nodes.set(value, vertex);
    return vertex;
  }

  addEdge(src, dest) {
    let srcNode = this.nodes.get(src);
    if (!srcNode) {
      srcNode = this.addVertex(src);
    }

    let destNode = this.nodes.get(dest);
    if (!destNode) {
      destNode = this.addVertex(dest);
    }

    srcNode.addAdjacent(destNode);
    if (this.directed === false) {
      destNode.addAdjacent(srcNode);
    }
  }
}

const g1 = new Graph();
g1.addVertex("a");
g1.addVertex("b");
g1.addEdge("a", "c");

When I console.log the graph object g1. I get the following output:

Graph {
  nodes: Map(3) {
    'a' => Node { value: 'a', adjacents: [Set] },
    'b' => Node { value: 'b', adjacents: Set(0) {} },
    'c' => Node { value: 'c', adjacents: [Set] }
  },
  directed: false
}

As output shows, I get no info regarding the edges of the vertices.

I tried passing replacer to JSON.stringify as follows, but it results in StackOverFlow error.

console.log(
  JSON.stringify(
    Object.fromEntries(g1.nodes),
    (_key, value) =>
      value.adjacents instanceof Set ? [...value.adjacents] : value,
    2
  )
);

Error:

  JSON.stringify(
       ^

RangeError: Maximum call stack size exceeded
    at JSON.stringify (<anonymous>)

How can I print the graph in a more friendly format?

Calculate coordinates of a square on different screen resolution javascript

I’m working on a project to detect the bounds of a QR Code on phone using react-native-qrcode-scanner library. On iOS devices, it shows the width, height and coordinates of the QR code so it’s pretty easy to work on. However, on Android devices, it returns the following bounds object:

{“height”: 1080, “origin”: [{“x”: “569.5”, “y”: “684.5”}, {“x”: “437.0”, “y”: “699.5”}, {“x”: “426.0”, “y”: “569.5”}, {“x”: “549.5”, “y”: “570.0”}], “width”: 1440}

The height and width is too large comparing to the scanned QR Code, and I guessed the objects inside origin array are the coordinates of 4 corners and I could calculate the width and height of the QR Code based on those coordinates. However when I’m done calculating the center point of the QR Code, it results the coordinates that are outside of the screen. So I think the coordinates are based on the height and width inside the above object and I want to calculate the coordinates based on the current device’s resolution, below is the image:
enter image description here

Thank you.

Discord OAuth identity endpoint not authorized after adding guilds scope?

Upon adding a guild scope to my Discord OAuth link, the authentication token in which responds does not have access to the identity (https://discord.com/api/users/@me) redirect.

My query parameters for the authentication is current as follows:

const queryParams = new URLSearchParams({
   client_id: AUTH_CLIENT_ID,
   redirect_uri: AUTH_REDIRECT,
   response_type: 'code',
   prompts: 'consent',
   scope: 'identify%20guilds',
   state: this.uuid,
})

let url = decodeURIComponent(`${AUTH_ENDPOINT}?${queryParams}`)

This link successfully prompts a discord authentication, asking if I would like give permissions, when I agree the link redirects me as expected.

I use the following code in order to receive a authentication token:
Where ‘auth’ is token returned from the redirect.

 const access_token = await request({
   method: 'POST',
   uri: TOKEN_ENDPOINT,
   form: {
      grant_type: 'authorization_code',
      code: auth,
      client_id: AUTH_CLIENT_ID,
      client_secret: AUTH_SECRET,
      redirect_uri: AUTH_REDIRECT
   },
   json: true
})

The following code is used to get the user identity. This is the request that responds invalid access!

const info = await request.get(USER_ENDPOINT, {
   headers: { Authorization: access_token.token_type + ' ' + access_token.access_token},
   json: true
})

Error!

{"message":"401: Unauthorized","code":0

Prior to adding the %20guilds scope, this worked fine.

Update:
For some reason it just seems to be my discord account that’s returning unauthorized, even on just the identity scope?

Javascript addEventListener() not working properly [closed]

I am trying to use addEventListener() to trigger a function when a button is clicked. For some reason, even though the DOM can access the element, and the addEventListener function is a defined property of the element, and I have already used it for many other things on the same page, it fails to add the event listener. There is no visible error message in the console at all. This code worked yesterday without any issues.

Here is my code:

// "output" is a predefined div

document.getElementById("output").innerHTML += `</div><div id="addDataWrapper"><button id="addData" class="option" style="width:170px;">Add Data</button></div>`;

document.getElementById("addDataWrapper").addEventListener("click", function(){
    console.log("this is a test");

    var newData = document.createElement("div");
    newData.innerHTML = `<div id="newDataContent">...</div>`; // some HTML here
    document.getElementById("editData").appendChild(newData);
});

I have simplified the code above (for example, the strings of HTML have been abbreviated for clarity), but that’s basically it. Looking at the chrome developer tools, it shows that there is no "click" event listener on the element at all.

I tried other things, such as putting all of this code inside another event listener to wait for the window to load or changing the variable names. The annoying thing is that if I change the element to add the event listener to:

...
document.getElementById("output").addEventListener("click", function(){...});
...

It works fine.

NOTE: I have read nearly every other StackOverflow question there is on this topic, and tried dozens of things. Nothing has worked.

jest test in react 18 failing because unable to find testid in react-dom, using createRoot

Using react 18 and looking to write jest tests with version 29.5.0. I’m getting this error when running my jest test TestingLibraryElementError: Unable to find an element by: [data-testid="/testdiv/i"] even though element was just rendered, I have also tried putting the expect inside an await waitFor. I’ve used a example div with a test id here as an example to simulate a component I’m importing

Is there a step I’m missing here to let the screen know how to find that test element?

package.json

 "react": "^18.2.0",
"jest": "^29.5.0",
"jest-environment-jsdom": "^29.5.0",

"jest": {
    "testEnvironment": "jsdom",
    "collectCoverage": true,
    "coverageReporters": [
      "html"
    ],
    "transform": {
      "^.+\.(t|j)sx?$": "@swc/jest"
    },
    "setupFiles": [
      "./jest.setup.js"
    ],
    "testEnvironmentOptions": {
      "browsers": [
        "chrome",
        "firefox",
        "safari"
      ]
    },
    "globals": {
      "IS_REACT_ACT_ENVIRONMENT": true
    }


jest.setup.js

import React from "react";
import { TextDecoder, TextEncoder } from "util";

global.React = React;
Object.assign(global, { TextDecoder, TextEncoder });

test file

import { JSDOM } from "jsdom";
import { createRoot } from "react-dom/client";
import { screen } from "@testing-library/react";

const dom = new JSDOM("<!doctype html><html><body></body></html>");
const document = dom.window.document;
const div = document.createElement("div");
div.id = "app";
document.body.appendChild(div);
const appElement = document.getElementById("app");
const root = createRoot(appElement!);

it("should render", () => {
    root.render(<div data-testid="testdiv">hi</div>);
    expect(screen.getByTestId(/testdiv/i)).toContain("hi");
  });

Is there a way to check if the password in an input element in currently made visible?

I am trying to animate something with input of a password element via JS. I want to differentiate between two animations depending on whether or not the password has been made visible by clicking on the standard ::-ms-reveal icon. I know that there is a work-around by adding a checkbox to show/hide the password and using element.type=="password" in JS instead. Since I would definately prefer the cleaner version without a checkbox, I was hoping to find a solution here.

Unfortunately I have not made much progress so far. Other than the work-around I descibed above, I tried to use the ::-ms-reveal as a pseudoclass , which unsurprisingly did not work though.

::-ms-reveal {
  transform: scale(0.5);
}

input {
  font-size: 1.5em;
  color: green;
}

input:focus {
  font-size: 2em;
  color: red;
}

input:has(::-ms-reveal:active) {
  color: yellow;
}
<form>
  <input type="password" placeholder="Type Password here!">
</form>

Other than that I did not have a great idea so far.

Manipulating div blocks through a function call in React

I am trying to create a react component that will render a ‘progress’ indicator based on the information I pass into the component. I realized for the project I am working on, I will need multiple “ProgressCircle” components on the same page and the javascript code I have for this to make it work targets the divs by id. When I did this on a html/js file, I was able to do this by assigning a different id to the divs and using multiple functions to run the setInterval function for the different progress circles. However, when I tried to convert my code to React, I keep getting errors such as relating to not being able to access the div by id.

I’m wondering if I am approaching this the correct way or if there is another solution.

Here is my code:


import React from "react";

function ProgressCircle( {endValue, specialID} ) {

    let progressBarID = 'progressBarID' + specialID;
    let valueContainerID = 'valueContainerID' + specialID;
    
    endValue = Math.floor( endValue );

    createProgressCircle( endValue, progressBarID, valueContainerID );

    return (
        <>
        <div className="progressDisplay">
            <div id={ progressBarID } className="progressBar">
                <div id={ valueContainerID } className="valueContainer"/>
            </div>
        </div>
        </>
    )
}

function createProgressCircle( endValue, progressBarID, valueContainerID ) {
    let progressBar = document.getElementById( progressBarID );
    let valueContainer = document.getElementById( valueContainerID );

    let progressValue = 0;
    let speed = 10;
    
    let progress = setInterval( () => {
        if ( endValue < 0) {
            valueContainer.innerText = '---';
            clearInterval( progress );
        } else {
            valueContainer.innerText = `${ endValue }%`;
            if ( endValue !== 0) {
                progressValue++;
            }
            if ( progress >= 100) {
                valueContainer.style.color = 'green';
                progressBar.style.background = 'green';
            } else {
                valueContainer.style.color = 'black';
                progressBar.style.background = `conic-gradient( 
                    #192A44 ${ progressValue * 3.6}deg,
                    #EEEEEE ${ progressValue * 3.6}deg
                )`
            }
        }
        if ( progressValue === endValue) {
            clearInterval( progress );
        }
    }, speed)
}

export { ProgressCircle }

Custom Formly Component not showing validation message on blur

I have a custom angular date picker component which uses ngb-datepicker and implements control value accessor. Now I create a formly component from this to use in my json form. This works fine but it’s not showing validation message when user clicks in control and clicks away. The control just stays untouched even though it was touched. It’s like blur is not triggered. What I am missing here?

Custom date picker control

import { Component, forwardRef, Input } from '@angular/core';
import {
  ControlValueAccessor,
  FormControl,
  NG_VALUE_ACCESSOR,
} from '@angular/forms';

@Component({
  selector: 'custom-date-picker',
  template: `
  <div class="input-group">
  <input
    class="form-control"
    placeholder="yyyy-mm-dd"
    name="dp"
    [formControl]="myControl"
    ngbDatepicker
    #d="ngbDatepicker"
    (keyup)="change($event)"
    (dateSelect)="change($event)"
  />
  <button
    class="btn btn-outline-secondary bi bi-calendar3"
    (click)="d.toggle()"
    type="button"
  ></button>
</div>
  `,
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => NgbdDatepickerPopup),
      multi: true,
    },
  ],
})
export class NgbdDatepickerPopup implements ControlValueAccessor {
  myControl = new FormControl();
  model = '';
  private _onChange = (value: unknown) => {};
  private _onTouch = (value: unknown) => {};

  writeValue(obj: any): void {
    this.myControl.setValue(obj);
  }
  registerOnChange(fn: any): void {
    this._onChange = fn;
  }
  registerOnTouched(fn: any): void {
    this._onTouch = fn;
  }

  change(event: unknown) {
    if (event instanceof Event) {
      const date = (event.target as HTMLInputElement).value;
      this._onChange(date);
      this._onTouch(date);
    }
  }
}

Formly Component

import { Component } from '@angular/core';
import { FieldType } from '@ngx-formly/core';

@Component({
 selector: 'formly-field-input',
 template: `
   <custom-date-picker [formControl]="formControl" [formlyAttributes]="field"></custom-date-picker>
   <div class="invalid-feedback" style="display: block;">
            <formly-validation-message *ngIf="showError" [field]="field"></formly-validation-message>
    </div>
 `,
})
export class FormlyFieldInput extends FieldType {}

Supabase Edge Functions not recognizing import map passed in `npx supabase functions serve`

I have two edge functions namely create-payment-link and retrieve-payment-link but the import map they’re using is /home/deno/flag_import_map.json, and not the import_map.json file in the functions folder. Thus they’re having a x was not mapped in import map. where x is a particular package they’re using.

Both functions have these imports:

import { serve } from "server"
import * as cryptojs from "crypto-js";

import { config } from "dotenv";

And the contents of import_map.json is:

{
  "imports": {
    "server": "https://deno.land/[email protected]/http/server.ts",
    "crypto-js": "https://cdn.skypack.dev/crypto-js",
    "dotenv": "https://deno.land/x/dotenv/mod.ts"
  }
}

This happens when trying to serve them both locally with: npx supabase functions serve --debug --env-file ./supabase/.env --import-map ./supabase/functions/import_map.json

Serving them one at a time with npx supabase functions serve function-name --debug --env-file ./supabase/.env works though

Transition duration not being homogeneous

Im working on a small game where a ball moves over the screen, using style.top = Math.random() and the same with style.left. However, when I specify the transition duration, at first it accelerates really quickly, and then moves to the specified place, and then really slowly slows down. I want the speed of the ball be the same throughout the whole movement.

Any ideas? Im looking for some sort of property to achieve this

Insert (changeable) html into modal using javascript’s ES6 Classes

I need some help implementing a javascript feature on this website that I’m developing.

The website have a section with some pictures of different persons. I want to open a modal with content related to that specific person, every time one clicks a picture. So, the content of the modal changes accordingly to the picture clicked.

So far I can make it work but can’t change the information accordingly to the picture I click on. I’m struggling to come up with a solution to change that html.
I’m using ES6 Classes and an array of objects to dtore the information about every person but I can’t find a way to make it work and not even sure if that’s the most efficient way.
The code, as it is, opens and closes the modal but doesn’t isert any html because it’s not complete, as I explained.
Any ideas?
Thank you for your help.

Here is my html:

<!-- members section -->
<section class="content-members section members hidden" id="section-2">
    <ul class="list-members">
        <li class="list-item list-item-content" data-id="1">
            <div class="item-primary">
                <div class="item-image">
                     <img loading="lazy" src="img/hr3_hi.png" alt="Adolfo Mesquita Nunes" class="image-hr">
                <div class="item-hovering"></div>
                    <div class="item-content">
                        <div class="text">
                            <h2>hvjhvjhv kjgkgkg kjhkjhkjh</h2>
                        </div>
                    </div>
                </div>
            </div>
        </li>
        <li class="list-item list-item-content" data-id="2"> … </li>
        <li class="list-item list-item-content" data-id="3"> … </li>
        <li class="list-item list-item-content" data-id="4"> … </li>
        <li class="list-item list-item-content" data-id="5"> … </li>
        <li class="list-item list-item-content" data-id="6"> … </li>
        <li class="list-item list-item-content" data-id="7"> … </li>
        <li class="list-item list-item-content" data-id="8"> … </li>
        <li class="list-item list-item-content" data-id="9"> … </li>
        <li class="list-item list-item-content" data-id="10"> … </li>
        <li class="list-item list-item-content" data-id="11"> … </li>
        <li class="list-item list-item-content" data-id="12"> … </li>
    </ul>
</section>

<!-- members popup -->
<div class="popup-members">
    <!-- 
    <div class="members-hero">
        <div class="members-hero-photo">
            <img src="" alt="members photo">
        </div>
        <div class="members-hero-content">
            <h1 class="members-hero-name"></h1>
            <p class="members-hero-presentation"></p>
            <a href="" class="members-hero-email"></a>
        </div>
    </div>
    -->
    <button class="members-hero-btn">&larr;</button>
</div>

And javascript:

const popupMembers = document.querySelector('.popup-members');
const members = document.querySelectorAll('.list-item');
const membersPage = document.querySelector('.members-hero');
const closeMembersPage = document.querySelector('.members-hero-btn');

// EVENTS AND FUNCTIONS
// individual members information --------------------
const membersList = [
  {
    id: '1',
    name: ‘fulano nunes',
    img: 'img/hr1_hi_NoBG.png',
    present: 'Minim sint mollit cillum ullamco proident occaecat ex Lorem consequat ea. Deserunt eiusmod enim elit exercitation. Minim eu anim in elit consequat. Sit nisi ea sint consectetur laborum nostrud. Tempor laborum ea culpa do eu exercitation irure labore nulla excepteur dolor.',
    email: '[email protected]'
  },
  {
    id: '2',
    name: ‘fulana joaquina',
    img: 'img/hr2_hi.png',
    present: 'Minim sint mollit cillum ullamco proident occaecat ex Lorem consequat ea. Deserunt eiusmod enim elit exercitation. Minim eu anim in elit consequat. Sit nisi ea sint consectetur laborum nostrud. Tempor laborum ea culpa do eu exercitation irure labore nulla excepteur dolor.',
    email: '[email protected]'
  },
  {
    id: '3',
    name: ‘fulana abrantes',
    img: '/img/hr3_hi.png',
    present: 'Minim sint mollit cillum ullamco proident occaecat ex Lorem consequat ea. Deserunt eiusmod enim elit exercitation. Minim eu anim in elit consequat. Sit nisi ea sint consectetur laborum nostrud. Tempor laborum ea culpa do eu exercitation irure labore nulla excepteur dolor.',
    email: '[email protected]'
  },
  {
    id: '4',
    name: 'fulana carvalho',
    img: '/img/hr4_hi.png',
    present: 'Minim sint mollit cillum ullamco proident occaecat ex Lorem consequat ea. Deserunt eiusmod enim elit exercitation. Minim eu anim in elit consequat. Sit nisi ea sint consectetur laborum nostrud. Tempor laborum ea culpa do eu exercitation irure labore nulla excepteur dolor.',
    email: '[email protected]'
  },
  {
    id: '5',
    name: 'fulana maria',
    img: '/img/hr5_hi.png',
    present: 'Minim sint mollit cillum ullamco proident occaecat ex Lorem consequat ea. Deserunt eiusmod enim elit exercitation. Minim eu anim in elit consequat. Sit nisi ea sint consectetur laborum nostrud. Tempor laborum ea culpa do eu exercitation irure labore nulla excepteur dolor.',
    email: '[email protected]'
  },
  {
    id: '6',
    name: 'fulana peniche',
    img: '/img/hr6_hi.png',
    present: 'Minim sint mollit cillum ullamco proident occaecat ex Lorem consequat ea. Deserunt eiusmod enim elit exercitation. Minim eu anim in elit consequat. Sit nisi ea sint consectetur laborum nostrud. Tempor laborum ea culpa do eu exercitation irure labore nulla excepteur dolor.',
    email: '[email protected]'
  },
  {
    id: '7',
    name: 'fulana cabana',
    img: '/img/hr7_hi.png',
    present: 'Minim sint mollit cillum ullamco proident occaecat ex Lorem consequat ea. Deserunt eiusmod enim elit exercitation. Minim eu anim in elit consequat. Sit nisi ea sint consectetur laborum nostrud. Tempor laborum ea culpa do eu exercitation irure labore nulla excepteur dolor.',
    email: '[email protected]'
  },
  {
    id: '8',
    name: 'fulano nunes',
    img: '/img/hr8_hi.png',
    present: 'Minim sint mollit cillum ullamco proident occaecat ex Lorem consequat ea. Deserunt eiusmod enim elit exercitation. Minim eu anim in elit consequat. Sit nisi ea sint consectetur laborum nostrud. Tempor laborum ea culpa do eu exercitation irure labore nulla excepteur dolor.',
    email: '[email protected]'
  },
  {
    id: '9',
    name: 'fulano nunes',
    img: '/img/hr9_hi.png',
    present: 'Minim sint mollit cillum ullamco proident occaecat ex Lorem consequat ea. Deserunt eiusmod enim elit exercitation. Minim eu anim in elit consequat. Sit nisi ea sint consectetur laborum nostrud. Tempor laborum ea culpa do eu exercitation irure labore nulla excepteur dolor.',
    email: '[email protected]'
  },
  {
    id: '10',
    name: 'fulana bárbara',
    img: '/img/hr10_hi.png',
    present: 'Minim sint mollit cillum ullamco proident occaecat ex Lorem consequat ea. Deserunt eiusmod enim elit exercitation. Minim eu anim in elit consequat. Sit nisi ea sint consectetur laborum nostrud. Tempor laborum ea culpa do eu exercitation irure labore nulla excepteur dolor.',
    email: '[email protected]'
  },
  {
    id: '11',
    name: 'fulana carvalho',
    img: '/img/hr11_hi.png',
    present: 'Minim sint mollit cillum ullamco proident occaecat ex Lorem consequat ea. Deserunt eiusmod enim elit exercitation. Minim eu anim in elit consequat. Sit nisi ea sint consectetur laborum nostrud. Tempor laborum ea culpa do eu exercitation irure labore nulla excepteur dolor.',
    email: '[email protected]'
  },
  {
    id: '12',
    name: 'fulana cabana',
    img: '/img/hr12_hi.png',
    present: 'Minim sint mollit cillum ullamco proident occaecat ex Lorem consequat ea. Deserunt eiusmod enim elit exercitation. Minim eu anim in elit consequat. Sit nisi ea sint consectetur laborum nostrud. Tempor laborum ea culpa do eu exercitation irure labore nulla excepteur dolor.',
    email: '[email protected]'
  }
];

// render members --------------------
class MembersIND {
  constructor(id, name, img, present, email) {
    this.id = id;
    this.name = name;
    this.img = img;
    this.present = present;
    this.email = email;
  };

  // render member
  renderMember (img, name, present, email) {
    let html =  `<div class="members-hero">
                  <div class="members-hero-photo">
                      <img src="${this.img}" alt="members photo">
                  </div>
                  <div class="members-hero-content">
                      <h1 class="members-hero-name">${this.name}</h1>
                      <p class="members-hero-presentation">
                          ${this.present}
                      </p>
                      <a href="mailto:[email protected]" class="members-hero-email">${this.email}</a>
                  </div>
                </div>`;
    membersPage.insertAdjacentHTML('afterbegin', html);
  };
};
// const someMember = new MembersIND();
// someMember.renderMember();

// members control --------------------
class MembersGEN {  
  constructor() {
    members.forEach(m => {m.addEventListener('click', this.openModal.bind(this))});
    closeMembersPage.addEventListener('click', this.closeModal.bind(this));
  };

  // show modal  
  openModal (e) {
    // detect member
    const memberId = e.target.closest('.list-item').getAttribute('data-id');
    // show modal
    popupMembers.style.display = 'block';
    // fade-in
    setTimeout(() => {
      popupMembers.style.opacity = '1';
    }, 100);
  };

  // close modal  
  closeModal() {
    // hide modal
    popupMembers.style.opacity = '0';
    // fade-out
    setTimeout(() => {
      popupMembers.style.display = 'none';
    }, 500);
  };
};
const member = new MembersGEN();

Remove a specific group of inputs in a form

I’m creating a form in which I need to clone with an “add” button a complete group/section of fields in my form, and also I need to delete them with a “delete” button.
The “add” button works perfectly, it means when I click add the complete group of fields are added correctly. But, when I click the “delete” button it remove all cloned group or the last one, and what I want to do is that if a click on the delete button of the second cloned group and there are five groups the second is deleted and not the last one or all cloned groups.

The HTML that I have is the following:

<div id=firstform>
<div class="card">
   <label class="label-nuevo-oficio" id="label-title">
       Title
   </label>
   <button type="button" class="btn btn-light" id="delete">
       delete 
   </button>
   <div>
     <div class="form-check form-check-inline">
          <input class="form-check-input" type="radio" name="tipoSolicitud" id="auth" value="yes">
     <label class="form-check-label" for="inlineRadio1">Autorización</label>
     </div>
     <div class="form-check form-check-inline">
          <input class="form-check-input" type="radio" name="tipoSolicitud" id="update" value="no">
     <label class="form-check-label" for="inlineRadio2">Actualización</label>
     </div>
     <label class="label-requis numero-oficio" id="label-numero-oficio">
            Number Oficio
     </label></br>
     <input class="form-control" type="text" name="num-oficio[]">
     <label class="label-requis fecha-emision" id="fecha-emision">
            Date
     </label></br>
     <input class="form-control" type="date" aria-label="default input example">
     <label class="label-requis fecha-tesoreria" id="fecha-tesoreria">
            Birthday
     </label></br>
     <input class="form-control" type="date" aria-label="default input example">
     <button type="button" class="btn btn-light" id="add">
       delete 
     </button>
   </div>
</div> 
</div>
<div id="new-form"></div>

For the add function that works correctly I implement the following using jquery:

$(document).ready(function (){
    $('button[id="add"]').on('click', function() {
        $('#firstform .card') 
            .clone(true, true)
            .attr('id', 'cloned_t')

            //To clone it empty  
            .find("input:text").val("").end()
            .find('input[type=radio]').prop('checked', false).end()
            .find('input[type=date]').val('00-00-0000').end()
            .find('input[type=number]').val('0.0').end()
            
            .appendTo('#new-form');
    });
});

For the delete function I’ve tried many things, but I always return to this which is basically what I have accomplished until now:

$(document).ready(function (){
    $('button[id="delete"]').on('click', function delete() {
        $("#new-form .card").remove();   
    });
});

But I’ve also tried with

$("#new-form .card").last().remove();

I’m wowndering if there’s a function like .last() but that delete the specific clone section that I want to delete. Or if there’s a way to put a different id for every cloned gorup. Or can someone help me to solve this problem with another solution.

Again, the problem is that when I add 5 groups, for example, and I want to delete the third group every cloned group is deleted or just the last one.

Thank you.

trying to update the cart icon status using javascript and django

So i am doing this small webpage project in Django and when its time to update the cart icon in the navbar, it doesn’t do anything. I had tried some alternatives but no change. Here is some part of my code. If any body can tell me what I’m missing that would be awesome. I’m pretty much a noob to this.

base.html where the navbar is

<!DOCTYPE html>
{% load static %}
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
    <link rel="stylesheet" href="{% static 'paginaV3_app/css/owl.carousel.min.css' %}">
    <link rel="stylesheet" href="{% static 'paginaV3_app/css/all.min.css' %}">
    <link rel="stylesheet" href="{% static 'paginaV3_app/css/myStyle.css' %}">
    <title>ChileFungi|{% block title %}{% endblock title %}</title>
</head>
<body>

    <nav id="nav-top" class="navbar navbar-expand-lg navbar-dark bg-success">
        <div class="container-fluid">
          <a class="navbar-brand" href="#"><img src="{% static 'paginaV3_app/imagenes/iconos/icono-pagina.png' %}" alt="" width="50" height="50" style="border-radius: 100%;"></a>
          <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
          </button>
          <div class="collapse navbar-collapse" id="navbarSupportedContent">
            <ul class="navbar-nav me-auto mb-2 mb-lg-0">
              <li class="nav-item">
                <a class="nav-link active" aria-current="page" href="/">Home</a>
              </li>
              <li class="nav-item dropdown">
                <a class="nav-link dropdown-toggle text-white" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
                  Productos
                </a>
                <ul class="dropdown-menu">
                  <li><a class="dropdown-item" href="{% url 'categoria' 'HG' %}">Hongos Gourmet</a></li>
                  <li><a class="dropdown-item" href="{% url 'categoria' 'EM' %}">Esporas Psilocybes</a></li>
                </ul>
              </li>
              <li class="nav-item">
                <a class="nav-link text-white" href="#">Contacto</a>
              </li>
              <li class="nav-item">
                <a class="nav-link text-white" href="{% url 'acerca' %}">Acerca de nosotros</a>
              </li>
            </ul>
            <form class="d-flex" role="search">
              <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
              <button class="btn btn-outline-success" type="submit">Search</button>
            </form>
          </div>
          <ul class="navbar-nav me-auto mb-2 mb-lg-0">
            <li class="nav-item dropdown mx-2">
              {% if user.is_authenticated %}
                <a class="nav-link dropdown-toggle text-white" href="#"
                  id="profileDropdown" role="button" data-bs-toggle="dropdown"
                  aria-expanded="false">{{ user.username }}</a>
                  <ul class="dropdown-menu" aria-labelledby="profileDropdown">
                      <li>
                          <a class="dropdown-item" href="{% url 'perfil' %}">Cuenta</a>
                      </li>
                      <li>
                          <a class="dropdown-item" href="{% url 'logout' %}">Salir</a>
                      </li>
                  </ul>
                  <li class="nav-item mx-2">
                    <a class="nav-link text-white" href="{% url 'mostrar_carrito' %}"> <span class="badge bg-danger" id="icono-carrito">0</span> Carrito </a>
                  </li>
              {% else %}
                <li class="nav-item mx-2">
                  <a class="nav-link text-white" href="{% url 'login' %}">Ingreso</a>
                </li>
                <li class="nav-item mx-2">
                  <a class="nav-link text-white" href="{% url 'registro' %}">Registro</a>
                </li>
                {% endif %}
                </li>
            </li>
          </ul>
        </div>
      </nav>
      
      {% block banner-carousel %}{% endblock banner-carousel %}
      {% block main-content %}{% endblock main-content %}
      
      <footer class="container-fluid fixed-bottom bg-success text-center text-white p2 mt-5">
        Copyright 2023: Geraldine Castro. Joaquín Godoy
      </footer>
    <script src="https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js" integrity="sha384-oBqDVmMz9ATKxIep9tiCxS/Z9fNfEXiDAYTujMAeBAsjFuCZSmKbSSUnQlmh/jp3" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-cuYeSxntonz0PPNlHhBs68uyIAVpIIOZZ5JqeqvYYIcEL727kskC66kF92t6Xl2V" crossorigin="anonymous"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
    <script src="{% static 'paginaV3_app/js/app.js' %}"></script>
    <script src="{% static 'paginaV3_app/js/owl.carousel.min.js' %}"></script>
    <script src="{% static 'paginaV3_app/js/all.min.js' %}"></script>
    
</body>
</html>

añadir_al_carrito.html

{% extends 'paginaV3_app/base.html' %}
{% load static %}
{% block title %}Carrito{% endblock title %}

{% block main-content %}
<div class="container my-5">
    <div class="row">
            <h1 class="text-center mb-5">Carrito de compras de {{ request.user }}</h1>
            <div class="col-sm-8">
                <div class="card">
                    <div class="card-body">
                        {% for item in items_carrito %}
                            <div class="row">
                                <div class="col-sm-3 text-center align-self-center"><img src="{{ item.producto.prod_imagen.url }}" alt="" class="img-fluid img-thumbnail shadow-sm" height="150" width="150"></div>
                                <div class="col-sm-9">
                                    <div>
                                        <h3>{{ item.producto.titulo }}</h3>
                                        <p class="mb-2 text-muted small">{{ item.producto.descripcion }}</p>
                                        <div class="my-3">
                                            <label for="cantidad">Cantidad</label>
                                            <a class="minus-cart btn" href="{% url 'disminuir_cantidad' item.id %}"><i class="fas fa-minus-square fa-lg"></i></a>
                                            <span id="cantidad">{{ item.cantidad }}</span>
                                            <a class="plus-cart btn" href="{% url 'aumentar_cantidad' item.id %}"><i class="fas fa-plus-square fa-lg"></i></a>
                                        </div>
                                        <div class="d-flex justify-content-between">
                                            <a href="{% url 'remover_del_carrito' item.id %}" class="remove-cart btn btn-sm btn-secondary ,r-3">Quitar Item</a>
                                            <p class="mb-0"><span><strong>${{ item.producto.precio }}</strong></span></p>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <hr class="text-muted">
                        {% empty %}
                        <h1 class="text-center mb-5">Carrito Vacío</h1>
                        {% endfor %}
                    </div>
                </div>
            </div>
            <div class="col-sm-4">
                <div class="card">
                    <div class="card-body">
                        <h3>Total de la Compra</h3>
                        <ul class="list-group">
                            <li class="list-group-item d-flex justify-content-between align-items-center border-0 px-0 pb-0">
                                <div>Subtotal:</div> <strong>$<span id="subtotal">{{ subtotal }}</span></strong>
                            </li>
                            <li class="list-group-item d-flex justify-content-between align-items-center border-0 px-0 mb-3">
                                <div>
                                    <strong>Total(+ 2800 de envío)</strong>
                                </div>
                                <strong>$<span class="" id="total"> {{ total }}</span></strong>
                                
                            </li>
                        </ul>
                        <div class="d-grid"><a href="#" class="btn btn-success">Pagar</a></div>
                    </div>
                </div>
            </div>
    </div>
</div>

{% endblock main-content %}

part of the views.py file (in the paginaV3_app folder)

@login_required
def añadir_al_carrito(request, prod_id):
    producto = Producto.objects.get(id=prod_id)
    carrito, created = Carrito.objects.get_or_create(
        user=request.user, producto=producto)
    if not created:
        carrito.cantidad += 1
        carrito.save()
    return redirect('mostrar_carrito')


@login_required
def remover_del_carrito(request, carrito_id):
    carrito = Carrito.objects.get(id=carrito_id)
    carrito.delete()
    return redirect('mostrar_carrito')


@login_required
def aumentar_cantidad(request, carrito_id):
    carrito = Carrito.objects.get(id=carrito_id)
    carrito.cantidad += 1
    carrito.save()
    return redirect('mostrar_carrito')


@login_required
def disminuir_cantidad(request, carrito_id):
    carrito = Carrito.objects.get(id=carrito_id)
    if carrito.cantidad > 1:
        carrito.cantidad -= 1
        carrito.save()
    return redirect('mostrar_carrito')


@login_required
def mostrar_carrito(request):
    items_carrito = Carrito.objects.filter(user=request.user)
    subtotal = sum(item.producto.precio *
                   item.cantidad for item in items_carrito)
    total = subtotal+2800
    context = {'items_carrito': items_carrito,
               'subtotal': subtotal, 'total': total}
    return render(request, 'paginaV3_app/añadir_al_carrito.html', context)

the urls

# Carrito
    path('añadir_al_carrito/<int:prod_id>', views.añadir_al_carrito, name='añadir_al_carrito'),
    path('carrito/', views.mostrar_carrito, name='mostrar_carrito'),
    path('remover_del_carrito/<int:carrito_id>',
         views.remover_del_carrito, name='remover_del_carrito'),
    path('aumentar_cantidad/<int:carrito_id>',
         views.aumentar_cantidad, name='aumentar_cantidad'),
    path('disminuir_cantidad/<int:carrito_id>',
         views.disminuir_cantidad, name='disminuir_cantidad'),

and the app.js

updateIconoCarrito();

function updateIconoCarrito(){
    $.get("{% url 'paginaV3_app:mostrar_carrito' %}", function(data){
        var itemCont =$(data).find("#cantidad").text()
        $("#icono-carrito").html(itemCont)
    })
}