Javascript stops responding on postback, DOMContentLoaded no longer responds

I’m not well-versed with Javascript, so please feel free to explain in detail. I’ve got this script that acts as a keystroke counter:

    <script type="text/javascript">

        document.addEventListener('DOMContentLoaded', function () {
            const textArea2 = document.getElementById('TextBox_Follow_Up_Answer2');
            const label1 = document.getElementById('Label_Answer_Char_Count');
            const label2 = document.getElementById('Label_Answer_Char_Count2');
            const labelRemaining1 = document.getElementById('Label_Answer_Char_Remaining');
            const labelRemaining2 = document.getElementById('Label_Answer_Char_Remaining2');

            // Add input event listener for text area
            textArea2.addEventListener('input', function () {
                textCounter(textArea2, 3000, label1, labelRemaining1);
                textCounter2(textArea2, 865, label2, labelRemaining2);
                alert("Event Listener - DOMContentLoaded");
            });
        });

        function textCounter(field, maxlimit, label, label2) {
            if (field.value.length > maxlimit)
                field.value = field.value.substring(0, maxlimit);
            else {

                label.innerHTML = maxlimit - field.value.length;
            }
            if (field.value.length > maxlimit - 500) {
                label.style.color = "#FF0000";
                label2.style.color = "#FF0000";
            }
            else {
                label.style.color = "#000000";
                label2.style.color = "#000000";
            }
            alert("textCounter Fired");
        }

        function textCounter2(field, maxlimit, label, label2) {
            if (field.value.length > maxlimit)
            //  field.value = field.value.substring(0, maxlimit);
            field.value = field.value;
            else {

                label.innerHTML = maxlimit - field.value.length;
            }
            if (field.value.length > maxlimit - 200) {
                label.style.color = "#FF0000";
                label2.style.color = "#FF0000";
            }
            else {
                label.style.color = "#000000";
                label2.style.color = "#000000";
            }
            alert("textCounter2 Fired");
        }

        $(document).ready(function () {
            alert("Page Initial Load");
            textCounter(textArea2, 3000, label1, labelRemaining1); // this works for initial page load only
            textCounter2(textArea2, 865, label2, labelRemaining2);
        });

        Sys.WebForms.PageRequestManager.getInstance().add_endRequest(function () {
            alert("Page Reload");
            textCounter(textArea2, 3000, label1, labelRemaining1); // this works after postback         
            textCounter2(textArea2, 865, label2, labelRemaining2);
        });

    </script>

On the same page, I have a button that creates an email based on certain info.

    <td>
        <asp:DropDownList ID="DropDownList_Response_Method" runat="server" Width="200px">
        </asp:DropDownList>
        <asp:Button ID="Button_Create_Email" runat="server" Text="Create Email" CssClass="action_button" Height="22px" Width="200px" OnClick="Button_Create_Email_Click" />
    </td>

The code-behind for this button is:

    protected void Button_Create_Email_Click(object sender, EventArgs e)
    {
        string question;
        string article;
        string section;

        //use question 3 details
        if (Label_Question_3_Text.Text != "")
        {
            question = WebUtility.HtmlDecode(Label_Question_3_Text.Text);
            article = Label_Question_3_Article_Number.Text;
            section = Label_Question_3_Section_Number.Text;
        }

        //use question 2 details
        else if (Label_Question_2_Text.Text != "")
        {
            question = WebUtility.HtmlDecode(Label_Question_2_Text.Text);
            article = Label_Question_2_Article_Number.Text;
            section = Label_Question_2_Section_Number.Text;
        }

        //use question 1 details
        else
        {
            question = WebUtility.HtmlDecode(Label_Question_1_Text.Text);
            article = Label_Question_1_Article_Number.Text;
            section = Label_Question_1_Section_Number.Text;
        }

        string answer = WebUtility.HtmlDecode(TextBox_Follow_Up_Answer2.Value);
        string answer_article = TextBox_Answer_Article_Number.Text;
        string answer_section = TextBox_Answer_Section_Number.Text;

        //remove special characters
        question = question.Replace("'", "");
        question = question.Replace("<", " less than ");
        question = question.Replace(">", " greater than ");
        question = question.Replace(""", "");
        question = question.Replace("&", "and");
        question = question.Replace(";", "");
        question = question.Replace("/", "");
        question = question.Replace("%", " percent");
        question = question.Replace("#", "number");
        question = question.Replace(System.Environment.NewLine, " ");

        answer = answer.Replace("'", "");
        answer = answer.Replace("<", " less than ");
        answer = answer.Replace(">", " greater than ");
        answer = answer.Replace(""", "");
        answer = answer.Replace("&", "and");
        answer = answer.Replace(";", "");
        answer = answer.Replace("/", "");
        answer = answer.Replace("%", " percent");
        answer = answer.Replace("#", "number");
        answer = answer.Replace(System.Environment.NewLine, " ");

        string account_name = Label_Account_Name.Text;
        //string account_number = Label_Account_Number.Text;

        Page.ClientScript.RegisterStartupScript(this.GetType(), "email", "parent.location='mailto:" + Label_Advocate_Name.Text + "?Subject=Coach Response for " + Label_Unique_ID.Text + " " + Label_Escalated.Text + " " + account_name +
            "&body=Analyst Question:  " + question +
            "%0D%0AAnalyst Article Number:  " + article +
            "%0D%0AAnalyst Section Number:  " + section +

            "%0D%0A %0D%0AAnswer:  " + answer +
            "%0D%0AAnswer Article:  " + answer_article +
            "%0D%0AAnswer Section:  " + answer_section +

            "%0D%0A %0D%0AREMINDER: If this answers your question, please accept the answer in the Question Response Page." +

            "'", true);

    }

So, what currently happens with the above code is, when the page loads I get an alert for “Page Initial Load”. I type a letter in the textbox and I get alerts for “textCounter Fired”, “textCounter2 Fired” and “Event Listener – DOMContentLoaded”. The counter decreases by 1. I type the next letter, and I get the same alerts, and again the counter decreases by 1. All is working well.

I click the Email button. It bypasses the “If (!IsPostBack)” block in my code-behind, so I know we’re dealing with a page postback. I continue stepping through the code, keeping an eye on my webpage and so far the character count on the page is fine. When I get to the last closing bracket of Button_Create_Email_Click, the webpage jumps to the top and the counters are reset to their default number.

When I close the email, I get no prompts. The javascript has stopped working. The counter doesn’t move, no alerts appear. I assume the listener has stopped listening? I added that last section of my Javascript because I saw a post that said you needed an add_EndRequest on Postback, but it doesn’t seem to work since I never see the alert inside that function. Related to that, I see this in the Debug window: “Uncaught ReferenceError ReferenceError: Sys is not defined”

Pass additional props to functional component

I have a constellation like this:

<AComponent>
  foo={{bar: AFunctionalComponent}}
</AComponent>
export default function AFunctionalComponent({
  // These are props that will get passed "automatically" by 'AComponent'
  foo, 
  bar, 
  baz
}) 
{...}

Now I want to pass an additional prop to AFunctionalComponent. How do I do that?

Radar Chart Color Transition and Border Smoothing Issue

“I am trying to make smooth color transitions in graphics using Radar Chart. At the same time, I want the lines to be smooth, but I cannot get the results I want. The color transitions are smooth, but the lines do not fit well and the corners look hard. You can find the code I used below. Does anyone have a helpful solution suggestion ?enter image description here

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Radar Chart with Smooth Color Transitions</title>
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
  <style>
    body {
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
      background-color: #252c37;
      margin: 0;
      font-family: Arial, sans-serif;
    }

    .chart-container {
      position: relative;
      width: 400px;
      height: 400px;
    }

    .center-text {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      text-align: center;
    }

    .main-number {
      font-size: 3em;
      color: #4CAF50;
    }

    .sub-text {
      font-size: 1.2em;
      color: #999;
    }
  </style>
</head>
<body>
  
  <div class="chart-container">
    <canvas id="radarChart"></canvas>
    <div class="center-text">
      <span class="main-number">87</span>
      <br />
      <span class="sub-text">Ad Liked</span>
    </div>
  </div>

  <script>
    // Özel plugin ile segmentleri renklendirme ve geçiş sağlama
    const multiColorPlugin = {
      id: 'multiColorPlugin',
      afterDatasetDraw(chart) {
        const { ctx } = chart;
        const meta = chart.getDatasetMeta(0);
        const points = meta.data;
        const tension = 0.3; // Daha yumuşak geçişler için tension

        const borderColors = [
          'rgba(255, 99, 132, 1)', // Pembe
          'rgba(54, 162, 235, 1)', // Mavi
          'rgba(255, 206, 86, 1)', // Sarı
          'rgba(75, 192, 192, 1)', // Turkuaz
          'rgba(153, 102, 255, 1)', // Mor
          'rgba(255, 159, 64, 1)'   // Turuncu
        ];

        ctx.save();
        for (let i = 0; i < points.length; i++) {
          const currentPoint = points[i];
          const nextPoint = points[(i + 1) % points.length];
          const prevPoint = points[(i - 1 + points.length) % points.length];

          // Kontrol noktaları hesaplanarak daha yumuşak geçiş sağlanıyor
          const cp1x = currentPoint.x + tension * (nextPoint.x - prevPoint.x);
          const cp1y = currentPoint.y + tension * (nextPoint.y - prevPoint.y);

          const gradient = ctx.createLinearGradient(currentPoint.x, currentPoint.y, nextPoint.x, nextPoint.y);
          gradient.addColorStop(0, borderColors[i]);
          gradient.addColorStop(1, borderColors[(i + 1) % points.length]);

          ctx.beginPath();
          ctx.moveTo(currentPoint.x, currentPoint.y);
          ctx.bezierCurveTo(cp1x, cp1y, nextPoint.x, nextPoint.y, nextPoint.x, nextPoint.y); // Daha yumuşak geçiş için bezierCurve
          ctx.strokeStyle = gradient;
          ctx.lineWidth = 3;
          ctx.stroke();
          ctx.closePath();
        }
        ctx.restore();
      }
    };

    // Radar grafiği verileri ve ayarları
    const data = {
      labels: ['Creativity', 'Originality', 'Emotion', 'Believable', 'Uniqueness', 'Different'],
      datasets: [{
        label: 'Ad Liked',
        data: [47, 91, 42, 88, 63, 83],
        fill: true,
        backgroundColor: 'rgba(0, 0, 0, 0.5)', // İç kısım siyah ve şeffaf
        pointBackgroundColor: 'rgba(0, 0, 0, 0)', // Noktaları gizle
        pointBorderColor: 'rgba(0, 0, 0, 0)', // Nokta kenarlarını gizle
        tension: 0.5 // Çizgilerin yumuşaklığı için tension
      }]
    };

    const config = {
      type: 'radar',
      data: data,
      options: {
        elements: {
          line: {
            borderWidth: 0 // Çizgi rengi plugin ile belirlenecek
          }
        },
        scales: {
          r: {
            angleLines: {
              display: false
            },
            suggestedMin: 0,
            suggestedMax: 100,
            ticks: {
              display: false // Etrafındaki sayıları gizler
            }
          }
        }
      },
      plugins: [multiColorPlugin] // Özel plugin kullanımı
    };

    // Radar grafiğini oluştur
    const radarChart = new Chart(
      document.getElementById('radarChart'),
      config
    );
  </script>

</body>
</html> Even though I made the transitions 0.5 to 0.5, it doesn't work.

Map pin background color 1st pin marker dissapears

I have the code below, the moment I place the second marker the 1st one is not rendered – Im stumped – if I remove the content: pinBackground.element both is rendered again

const pinBackground = new PinElement({
background: “#FBBC04”,
});

new google.maps.marker.AdvancedMarkerElement({
map,
title: ‘wittebergstudio’,
content: pinBackground.element,
position: {
lat: -28.507,
lng: 27.933
}
});

new google.maps.marker.AdvancedMarkerElement({
map,
title: ‘rusendalcottages’,
content: pinBackground.element,
position: {
lat: -28.506,
lng: 27.940
}
});

different color pins/marker

Automated Subscription and Rental Management [closed]

I’m managing game subscriptions and rentals manually and looking for an easier and faster way to handle it. I need a system or tool that can help with:

1- Tracking the start and end dates of each subscription.
2- Storing subscription emails and customer contact info like phone numbers or emails.

How would you recommend I go about this?

I hope to find a more automated solution to simplify and streamline the process

Change of property value of an object instance is affecting others objects as well

When I change the values of a property of an instance of an object, I find that the other instances of the object have the value of that specific property changed too. Look at my code and you’ll see.

window.onload = function() {

    function randomInt(min, max) {
        return Math.floor(Math.random() * (max - min + 1) ) + min;
    }

    let canva1 = document.getElementById("canva1");
    
    let canvaWidth = 600;
    let canvaHeight = 500;

    canva1.width = canvaWidth;
    canva1.height = canvaHeight;
    canva1.style.border = "1px solid black";

    let ctx = canva1.getContext("2d");

    const Bola = {
        x: null,
        y: null,
        raio: randomInt(10, 30),
        direcaoX: null,
        direcaoY: null,
        gerarBola: function() {

            if (this.direcaoX == null) {
                let a = randomInt(0, 1);
                if (a == 0) {
                    this.direcaoX = false;
                }
                else {
                    this.direcaoX = true;
                }
            }
            if (this.direcaoY == null) {
                let a = randomInt(0, 1);
                if (a == 0) {
                    this.direcaoY = false;
                }
                else {
                    this.direcaoY = true;
                }
            }

            if (this.x == null) {
                this.x = randomInt(this.raio, canvaWidth-this.raio);
            }
            if (this.y == null) {
                this.y = randomInt(this.raio, canvaHeight-this.raio);
            }
            
            ctx.clearRect(0, 0, canvaWidth, canvaHeight);

            ctx.beginPath();
            ctx.arc(this.x, this.y, this.raio, 0, 2*Math.PI);
            ctx.fillStyle = "rgb(" + randomInt(0, 255) + "," + randomInt(0, 255) + "," + randomInt(0, 255) + ")";
            ctx.fill();
            ctx.strokeStyle = "rgb(" + randomInt(0, 255) + "," + randomInt(0, 255) + "," + randomInt(0, 255) + ")";
            ctx.stroke();

            if (this.x+this.raio < canvaWidth && this.direcaoX == true) {
                this.x++;
            }
            else if (this.x+this.raio >= canvaWidth && this.direcaoX == true) {
                this.x--;
                this.direcaoX = false;
            }
            else if (this.x-this.raio > 0 && this.direcaoX == false) {
                this.x--;
            }
            else if (this.x-this.raio <= 0 && this.direcaoX == false) {
                this.x++;
                this.direcaoX = true;
            }

            if (this.y+this.raio < canvaHeight && this.direcaoY == true) {
                this.y++;
            }
            else if (this.y+this.raio >= canvaHeight && this.direcaoY == true) {
                this.y--;
                this.direcaoY = false;
            }
            else if (this.y-this.raio > 0 && this.direcaoY == false) {
                this.y--;
            }
            else if (this.y-this.raio <= 0 && this.direcaoY == false) {
                this.y++;
                this.direcaoY = true;
            }
        }
    }

    let bola1 = Bola;
    let bola2 = Bola;
    let bola3 = Bola;
    let bola4 = Bola;
    let bola5 = Bola;

    setInterval(function() {
        bola1.gerarBola();
        bola2.gerarBola();
        bola3.gerarBola();
        bola4.gerarBola();
        bola5.gerarBola();

        console.log("Bola 1: " + bola1.x);
        console.log("Bola 2: " + bola2.x);
        console.log("Bola 3: " + bola3.x);
        console.log("Bola 4: " + bola4.x);
        console.log("Bola 5: " + bola5.x);
        
    }, 500);

}

Now, let me explain. I’m trying to create multiples instances of a moving ball using canvas. 5 of them, to be clear. I’ve created a “Bola” object with its own properties, so it doesn’t affect other instances. Btw, there’s also an index.html, but the only thing it have is a div with a “canva1” id.
I think the code is pretty self-explanatory. Try to execute it, and you’ll see what I’m talking about.
Also, the “500” in the end is how fast the ball is moving. I made it that slow so you can see in the console that all the balls are in the same position (or something like that). And, with every “ball” I add, the only thing happening is the one ball accelerating.
Btw.: Sorry for my bad english :p

I have no idea how to go further. After I created one ball, I tried what you can see in the “setInterval” part. It hasn’t created more ball. It only made x and y go +5 instead of the normal +1 (one per instance). Look at the console log, and try to delete the number of balls in the few last lines, and you’ll see.

Hide iframe in the absence of its stylesheet

I have an iframe with the following element in its header

<link type="text/css" rel="stylesheet" href="/web/assets/report.min.css">

The problem is that this style sheet takes more time to load than the iframe. Because of that, the iframe would show without styling for 2 seconds or so.

What I want to do is to hide the iframe and only show it if this style sheet has fully loaded. How can I do this? Can I maybe listen to the url /web/assets/report.min.css and once it returns status code of 200 I can show the iframe?

How can i remove everything after the domain(3dmks.eu/(this))?

Im trying to remove everything that comes after the .eu

The webpage is made in multiple sections and how u scroll u will notice the page is pulling sections.

I would like to remove it but i dont know how and i cant find how to do it or implement it,

U can check the website and see what i mean when u scroll down the sections. 3dmks.eu

Thank you.

let url = "3dmks.eu/some/path";
let result = url.split(".eu")[0] + ".eu";
console.log(result); // Output: "3dmks.eu"
let url = "3dmks.eu/some/path";
let result = url.replace(/.eu.*/, ".eu");
console.log(result); // Output: "3dmks.eu"

I tried this but didn’t work out.

Angular FormGroup values not updating in DOM with patchValue()

I have a FiltersAccordion component to manage table filtering. This component is pretty complex due to the fact that the users must be able to group filters in AND & OR groups. My current file structure is:

  • FiltersAccordion: manages the overall “save filters” logic.
  • FiltersBlock: displays a list of filters grouped by an AND.
  • Filter: each one of the filters, consists of one or more inputs/selects/checkbox.

The goal is that each one of those Filters can be drag&dropped from a FilterBlock to another one. The main problem right now is that the “new filter” added to the drop destination block retains all the correct data, but is not reflecting it in the form values in the DOM.

This is the code for the FilterBlock component. Here filterGroups is an array of FormGroups which is looped in the <ul>:

// filters-block.component.html

<ul
  class="filter__group__list"
  (dragover)="handleDragOver($event)"
  (drop)="handleDrop($event)"
>
  <li
    class="filter__group__item"
    draggable="true"
    *ngFor="let group of filterGroups; let idx = index"
  >
    <app-filter
      (change)="handleUpdateFilter($event, idx)"
      [columnsService]="columnsService"
      [data]="data"
      [defaultValues]="group"
      (dragStart)="handleDragStart($event, idx)"
      (dragEnd)="handleDragEnd($event, idx)"
      (removeFilter)="handleRemoveFilter(idx)"
    ></app-filter>
  </li>
</ul>
// filters-block.component.ts

// * Filters grouped by AND operator
export class FiltersBlockComponent implements OnInit {
  @Output() dragStart = new EventEmitter<{ event: DragEvent; item: number }>();
  @Output() dragEnd = new EventEmitter<{ event: DragEvent; item: number }>();
  @Output() removeBlock = new EventEmitter<void>();

  public filterGroups: FormGroup<FilterGroupTO>[];

  constructor() {}

  ngOnInit() {
    this.filterGroups = [
      new FormGroup<FilterFormGroupTO>({
        checkBox: new FormControl<boolean | null>(false),
        field: new FormControl<FilterableColumnsTO | null>(null),
        relation: new FormControl<string | null>(''),
        value: new FormControl<FilterableColumnsTO | null>(null),
      }),
    ];
  }

  handleUpdateFilter(filter: FilterFormGroupTO, index: number) {
    this.filterGroups[index].patchValue(filter as any);
  }

  handleRemoveFilter(index: number) {
    this.filterGroups.splice(index, 1);

    if (this.filterGroups.length === 0) {
      this.removeBlock.emit();
    }
  }

  handleDragStart(event: DragEvent, index: number) {
    this.dragStart.emit({ event, item: index });
  }

  handleDragEnd(event: DragEvent, index: number) {
    this.dragEnd.emit({ event, item: index });
  }

  handleDragOver(event: DragEvent) {
    event.preventDefault();
    if (event.dataTransfer) event.dataTransfer.dropEffect = 'move';
  }

  handleDrop(event: DragEvent) {
    event.preventDefault();
    if (event.dataTransfer) {
      const filterData = event.dataTransfer.getData('filter');
      const properFilter = JSON.parse(filterData);

      const newGroup = new FormGroup<FilterFormGroupTO>({
        checkBox: new FormControl<boolean | null>(properFilter.checkBox),
        field: new FormControl<FilterableColumnsTO | null>(properFilter.field),
        relation: new FormControl<string | null>(properFilter.relation),
        value: new FormControl<FilterableColumnsTO | null>(properFilter.value),
      });
      this.filterGroups.push(newGroup);
    }
  }
}

The Filter component contains all the form logic and inputs:

<div
  [formGroup]="filterFormGroup"
  class="filter__group__item"
  [draggable]="enableDrag"
  (dragstart)="handleDragStart($event)"
  (dragend)="handleDragEnd($event)"
>
      <select
        formControlName="field"
      >
        <option
          *ngFor="let option of filtersColumns"
          [displayValue]="option.fieldName"
          [readValue]="option"
          >{{ option.fieldName }}</option
        >
      </select>
      <select
        formControlName="relation"
      >
        <option
          *ngFor="
            let option of filterFormGroup.controls['field'].value?.operations;
            let i = index
          "
          [readValue]="option"
          >{{
            "DIALOGS.FILTERS.RELATION." + option | translate
          }}</option
        >
      </select>
      <select
        formControlName="value"
      >
        <option
          *ngFor="let option of fieldDistincValues; let i = index"
          [displayValue]="option"
          [readValue]="option"
          >{{ option }}</option
        >
      </select>
      <input
        formControlName="value"
        type="text"
      ></input>
    </div>
    <app-toggle
      formControlName="checkBox"
      [label]="'DIALOGS.FILTERS.CHECKBOX' | translate"
    ></app-toggle>
</div>
// filter.component.ts

export interface FilterFormGroupTO {
  field: FormControl<FilterableColumnsTO | null>;
  relation: FormControl<string | null>;
  value: FormControl<FilterableColumnsTO | null>;
  checkBox: FormControl<boolean | null>;
}

export class FilterComponent implements OnInit {
  @Output() change = new EventEmitter<FilterFormGroupTO>();
  @Output() dragStart = new EventEmitter<DragEvent>();
  @Output() dragEnd = new EventEmitter<DragEvent>();
  @Output() removeFilter = new EventEmitter<void>();
  @Input() defaultValues: FormGroup<FilterFormGroupTO>;

  // filters
  private selectedFilters: FilterTO[] = [];
  public availableFilters: Columns[] = [];

  // form
  public filterFormGroup: FormGroup<FilterFormGroupTO>;

  constructor(filtersService: FiltersService) {}

  ngOnInit() {
    // Initialize form. NOT WORKING
    this.filterFormGroup = new FormGroup<FilterFormGroupTO>({
      checkBox: new FormControl<boolean | null>(
        this.defaultValues.value.checkBox as boolean | null
      ),
      field: new FormControl<FilterableColumnsTO | null>(
        this.defaultValues.value.field as FilterableColumnsTO | null
      ),
      relation: new FormControl<string | null>(
        this.defaultValues.value.relation as string | null
      ),
      value: new FormControl<FilterableColumnsTO | null>(
        this.defaultValues.value.value as FilterableColumnsTO | null
      ),
    });

    // Patch form values. NOT WORKING
    this.filterFormGroup.patchValues({
      checkBox: this.defaultValues.value.checkBox as boolean | null,
      field: this.defaultValues.value.field as FilterableColumnsTO | null,
      relation: this.defaultValues.value.relation as string | null,
      value: this.defaultValues.value.value as FilterableColumnsTO | null,
    });

    // Get available filters
    filtersService().subscribe((res) => {
      this.availableFilters = res;
    });

    // Changes in form listener
    this.filterFormGroup.valueChanges.subscribe((value) => {
      this.change.emit(value as unknown as FilterFormGroupTO);
    });
  }

  handleRemoveFilter() {
    this.removeFilter.emit();
  }

  handleDragStart(event: DragEvent) {
    const fieldValue = this.filterFormGroup.value['field'];
    const checkboxValue = Boolean(this.filterFormGroup.value['checkBox']);
    const relationValue = this.filterFormGroup.value['relation'];
    const valueValue = this.filterFormGroup.value['value'];

    const data = {
      checkBox: checkboxValue,
      field: fieldValue,
      relation: relationValue,
      value: valueValue,
    };

    if (this.enableDrag) {
      event.dataTransfer?.setData('filter', JSON.stringify(data));

      if (event.dataTransfer) event.dataTransfer.effectAllowed = 'move';
      this.dragStart.emit(event);
    }
  }

  handleDragEnd(event: DragEvent) {
    if (this.enableDrag) {
      this.dragEnd.emit(event);

      if (event.dataTransfer?.dropEffect === 'move') {
        this.handleRemoveFilter();
      }
    }
  }
}

As I pointed out, the ngOnInit of the Filter component does does carry the correct data when I log it. Even when I console.log(this.filterFormGroup) I’m getting the correct values. Why are they not being rendered in the DOM?

Am I approaching this the wrong way? I’m new to Angular forms and this is the best I could manage. Thanks.

Variable not accessible in navbar.ejs after connecting MongoDB online database

I am working on an Airbnb-like project using Express.js. Initially, everything worked fine, including passing variables to navbar.ejs using middleware. However, after connecting to an online MongoDB database, I started encountering the following issue:

21| <%- include(“../includes/navbar.ejs”) %>
The variable that I expect to access in navbar.ejs is no longer available. I have followed the correct syntax and used an npm package for handling local variables in Express, but the error persists.

Here are the steps I followed:

Created middleware to pass variables to all routes.
Tried using the include statement in my views to reference navbar.ejs.
Connected MongoDB via Mongoose with a proper connection string.
Before connecting to MongoDB, everything was working as expected, so I’m not sure what changed.

What does mean in this http.get?

  getBooks(): Observable<Array<Books>> {

    return this.http
      .get<{ items: Books[] }>(
        'https://www.googleapis.com/books/v1/volumes?maxResults=5&orderBy=relevance&q=oliver%20sacks'
      )
      .pipe(map((books) => books.items || []));
  }

Trying to understand the TypeScript syntax here:

.get<{ items: Books[] }>(

Does this mean that first it gets the URL and does a map filter operator on it, then it’s returning an object that only contains an items property with the interface Books[]?

Display base64 content in browser in React

I’m trying to use the following package as I have multiple file types that I need to display (word docs, pdf, png) https://www.npmjs.com/package/react-doc-viewer#idocument

I’m getting file data as base64 from the backend. Example (this is not the entire base64 content):
UEsDBBQABgAIAAAAIQDfpNJsWgEAACAFAAATAAgCW0NvbnRlbnRfVHlwZXNdLnhtbCCiBAIooAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC0lMtuwjAQRfeV+g+Rt1Vi6KKqKgKLPpYtUukHGHsCVv2Sx7z+vhMCUVUBkQpsIiUz994zVsaD0dqabAkRtXcl6xc9loGTXmk3K9nX5C1/ZBkm4ZQw3kHJNoBsNLy9GUw2ATAjtcOSzVMKT5yjnIMVWPgAjiqVj1Ykeo0zHoT8FjPg973eA5feJXApT7UHGw5eoBILk7LXNX1uSCIYZNlz01hnlUyEYLQUiep86dSflHyXUJBy24NzHfCOGhg/mFBXjgfsdB90NFEryMYipndhqYuvfFRcebmwpCxO2xzg9FWlJbT62i1ELwGRztyaoq1Yod2e/ygHpo0BvDxF49sdDymR4BoAO+dOhBVMP69G8cu8E6Si3ImYGrg8RmvdCZFoA6F59s/m2NqciqTOcfQBaaPjP8ber2ytzmngADHp039dm0jWZ88H9W2gQB3I5tv7bfgDAAD//wMAUEsDBBQABgAIAAAAIQAekRq37wAAAE4CAAALAAgCX3JlbHMvLnJlbHMgogQC…

This package says to transform the data into a list of IDocument, which I am setting the uri property with the base64 data. I have tried many different forms and haven’t found anything that works

I’ve tried decoding the base64, converting it to a file and using the url path, including the file type as part of the base64 string (data:image/png;base64,base64string)

Uncaught Error: Type “function MediaStream() { [native code] }” not yet supported in PeerJS

I’m working on a video conferencing application using PeerJS, and I’m encountering an issue when trying to pass a video stream to another peer. The error I’m getting is:

Uncaught Error: Type "function MediaStream() { [native code] }" not yet supported

Here are the relevant parts of my code:
Peer.ts

addStream(stream: MediaStream) {
    console.log('Adding stream to peers:', stream);
    Object.values(this.peers).forEach(peer => {
        const call = this.peer.call(peer.conn.peer, stream, {
            metadata: { username: 'Video', video: true, audio: true }
        });

        call.on('stream', peerStream => {
            console.log('Received peer stream:', peerStream);
            this.emit('peer', {
                id: call.peer,
                username: 'Video',
                stream: peerStream,
                video: true,
                audio: true
            });
        });

        this.peers[peer.conn.peer].media = call;
    });

    this.emit('peer', {
        id: 'video',
        username: 'Video',
        stream: stream,
        video: true,
        audio: true
    });

    // Emit an event to notify peers
    Object.values(this.peers).forEach(peer => {
        if (peer.conn) {
            peer.conn.send({
                type: 'add-stream',
                data: { streamId: STATIC_STREAM_ID } // Use static stream ID
            });
        }
    });
}

handleAddStream(streamId: string) {
    console.log('Handling added stream:', streamId);
    if (streamId === STATIC_STREAM_ID) {
        const stream = this.hostStream;

        if (stream) {
            console.log('Stream found:', stream);
            this.emit('peer', {
                id: 'video',
                username: 'Video',
                stream: mediaStream,
                video: true,
                audio: true
            });
        } else {
            console.error('Stream not found:', streamId);
        }
    } else {
        console.error('Invalid stream ID:', streamId);
    }
}

Host.ts:

addStream(stream: MediaStream) {
    console.log('Adding stream to peers:', stream);
    Object.values(this.peers).forEach(peer => {
        const call = this.peer.call(peer.conn.peer, stream, {
            metadata: { username: 'Video', video: true, audio: true }
        });

        call.on('stream', stream => {
            console.log('Received peer stream:', stream);
            this.emit('peer', {
                id: STATIC_STREAM_ID,
                username: 'Video',
                stream: stream,
                video: true,
                audio: true
            });
        });

        this.peers[peer.conn.peer].media = call;
    });

    console.log('Added stream to peers:', stream);
    this.emit('peer', {
        id: 'video',
        username: 'Video',
        stream: stream,
        video: true,
        audio: true
    });
    this.passSpecialString(stream.id)
    this.passMediaStream(stream);

    // Emit an event to notify peers
    Object.values(this.peers).forEach(peer => {
        if (peer.conn) {
            peer.conn.send({
                type: 'add-stream',
                data: { streamId: STATIC_STREAM_ID } // Use static stream ID
            });
        }
    });
}

passMediaStream(mediaStream: MediaStream) {
    Object.values(this.peers).forEach(peer => {
        if (peer.conn) {
            peer.conn.send({
                type: 'media-stream',
                data: { stream: mediaStream }
            });
        }
    });
}

I’ve tried to ensure that the MediaStream object is correctly passed and handled, but I keep encountering this error. Any insights on what might be causing this issue and how to resolve it would be greatly appreciated.

Implementing gsap scroll animation in React project

I’m trying to implement a section which actually has the same logic as in brainsave.ai, the third section with Core Feature. In my case, the right side is replaced with bubbles and left side is pretty similar to the reference.

However, I’m having a problem with scroll animation as in our project it just goes to third index if I try to scroll a bit and animation is not right completely.

I’m using gsap to implement this in React application. So, I have some state to track several things:

  const bulletRef = useRef(null);
  const [isLargeScreen, setIsLargeScreen] = useState(false);
  const textRefs = useRef([]); // array to hold the elements on the left
  const bubbleRefs = useRef([]); // array to hold the elements on the right
  const mainS = useRef(null); // main section ref 
  const [activeDot, setActiveDot] = useState(0); // to check the current bulletpoint

I’m using useEffect to trigger the scroll for gsap:

useEffect(() => {
    if (isLargeScreen) {
      const tl = gsap.timeline({
        scrollTrigger: {
          trigger: mainS.current,
          start: "top top",
          scrub: 5,
          pin: true,
        },
      });

      textRefs.current.forEach((text, i) => {
        const nexttext = textRefs.current[i + 1];
        if (!(i === textRefs.current.length - 1)) {
          tl.to(
            text,
            {
              top: "-110%",
              duration: 2,
              ease: "power3.inOut",
              opacity: 0,
            },
            `${i}key`
          ).to(
            nexttext,
            {
              // delay: 0,
              duration: 2.1,
              top: 0,
              ease: "power3.inOut",
            },
            `${i}key`
          );
        }
      });

      bubbleRefs.current.forEach((bubble, i) => {
        const nextBubble = bubbleRefs.current[i + 1];

        if (!(i === bubbleRefs.current.length - 1)) {
          tl.to(
            bubble,
            {
              top: "150%",
              duration: 2,
              ease: "power3.inOut",
              opacity: 0,
            },
            `${i}key`
          ).to(
            nextBubble,
            {
              // delay: 0,
              duration: 2.1,
              top: 0,
              ease: "power3.inOut",
            },
            `${i}key`
          );
        }

      });
    }
  }, [isLargeScreen]);

and I also have useEffect for getting the screen size and setting isLargeScreen.

and I return the code:

return (
    <ReactLenis root options={lenisOptions}>
      <div className={style.main}>
        <section className={style.work} ref={mainS}>
          {isLargeScreen ? (
            <>
              <div className={style.work_left}>
                <div className={style.work_text}>
                  {WORK_ITEMS.map((item, index) => (
                    <div
                      id={`slide_${index}`}
                      ref={(el) => textRefs.current.push(el)}
                      key={index}
                      className={`text${index} ${style.work_info}`}
                    >
                      <div className={style.work_left_bl}>
                        <div className={style.core_btn}>
                          <div className={style.feature_btn}>Core Feature</div>
                          <h4 className={style.work_num}>{item.num}</h4>
                        </div>
                        <div className={style.svg_container}>
                          <h2 className={style.title}>{item.title}</h2>
                          <div className={style.desc}>{item.description}</div>
                        </div>
                      </div>
                      <div className={style.left_side_logo}>
                        {LOGO_LIST.map((i, e) => (
                          <img src={`/images/${i}`} />
                        ))}
                      </div>
                    </div>
                  ))}
                  {/* </ReactLenis> */}
                </div>
                <div className={style.pagination}>
                  {WORK_ITEMS.map((item, index) => (
                    <div
                      key={index}
                      className={`${style.dot} ${activeDot === index ? style.active : ""
                        }`}
                      onClick={() => handleDotClick(index)}
                    ></div>
                  ))}
                </div>
              </div>
              <div className={style.work_right} ref={bulletRef}>
                <div className={style.work_right_b1}>
                  <div className={style.container}>
                    {SECTION_CONTENT.map((group, groupIndex) => (
                      <div
                        ref={(el) => bubbleRefs.current.push(el)}
                        className={`bubble${groupIndex} ${style.bubbles_container}`}
                      >
                        {group.map((item, itemIndex) => (
                          <div
                            key={`${groupIndex}-${itemIndex}`}
                            className={` ${style.bubble} ${style[`bubble${itemIndex + 1}`]
                              }`}
                          >
                            {item}
                          </div>
                        ))}
                      </div>
                    ))}
                  </div>
                </div>
              </div>
            </>
          ) : (
            <div className={style.mobile_view}>
              {WORK_ITEMS.map((item, index) => (
                <div key={index} className={style.mobile_feature}>
                  <div className={style.work_info}>
                    <div className={style.work_left_bl}>
                      <div className={style.core_btn}>
                        <div className={style.feature_btn}>Core Feature</div>
                        <h4 className={style.work_num}>{item.num}</h4>
                      </div>
                      <div className={style.svg_container}>
                        <h2 className={style.title}>{item.title}</h2>
                        <div className={style.desc}>{item.description}</div>
                      </div>
                    </div>
                  </div>
                  <div className={style.container}>
                    {SECTION_CONTENT[index].map((e, i) => (
                      <div
                        className={`${style.bubble} ${style[`bubble${i + 1}`]}`}
                      >
                        {e}
                      </div>
                    ))}
                  </div>
                  <div className={style.left_side_logo}>
                    {LOGO_LIST.map((i, e) => (
                      <img src={i} />
                    ))}
                  </div>
                </div>
              ))}
            </div>
          )}
        </section>
      </div>
    </ReactLenis>
  );

So, it check if the screen is either larger or small to place the content correctly.

I’m having following issues though:
0. it should take whole height (100vh) if the section and once I’m in first element it should scroll within the elements of array (same as in brainsave.ai

  1. animation is not correct: when I scroll it just goes too fast and does not stop in second index, but goes up to third
  2. clicking to bulletpoint does not work right: it just makes the animation crazy while going to next/previous item
  3. responsiveness does not really work: if I make the screen smaller then content on the right side is having problem with placement

I have added the code to codesandbox if you would like to check it.

How to use previous state for showing previous card items with react native?

I have a React Native web app with a card item that shows category items. For example, parrots can have multiple categories, like: parrots1, parrots2, parrots3. If a user clicks on parrots1, this category can also have multiple subcategories, such as: parrots1.1, parrots1.2, etc. It’s a one-to-many relationship.

A user can click on a card item and be navigated to the next card items with the categories. For example, category item 1 has subcategories: 1, 3, 5. This works fine.

Now, I want to implement a back button so that the user can return to the previous card items. I implemented a previous state reference using the useEffect hook, like this:

  useEffect(() => { 
    if (previousStateRef.current) {
      console.log("Previous state:", previousStateRef.current);
    }
  
    // Update ref to current state after render
     previousStateRef.current = subCatgoryList;
  }, [subCatgoryList]);

I can retrieve the previous state items, but I need to use this previous state with a button so that the user can see the previous card items.

I implemented a function to update the previous state reference, like this:

  const updatePreviousStateRef = (currentState) => {
    if (previousStateRef.current) {
      console.log("Previous state:", previousStateRef.current);
    }   
    previousStateRef.current = currentState;
  };

And I created a button for using that function:

 <Button icon="arrow-left" mode="contained" onPress={updatePreviousStateRef}>
        Back to Card
 </Button>

But this does not work. If a user press on the button. This will be returned:

Previous state: SyntheticBaseEvent {_reactName: 'onClick', _targetInst: null, type: 'click', nativeEvent: PointerEvent, target: div.css-text-146c3p1.r-maxWidth-dnmrzs.r-overflow-1udh08x.r-textOverflow-1udbk01.r-whiteSpace-3s2u2…, …}

So for brevity, this is the whole code:

import { ActivityIndicator, Pressable, StyleSheet, View } from "react-native";
import { Button, MD2Colors, Searchbar } from "react-native-paper";
import {
  CategoryList,
  LoadingContainer,
} from "/src/components/general/view-flatlist-card";
import React, { useContext, useEffect, useRef, useState } from "react";

import { AccordionCategoryItemsContext } from "../../../services/accordian-category-items.context";
import { AccordionItemsContext } from "../../../services/accordion-items.context";
import { AnimalDetailToggle } from "../../../components/general/animal-detail-toggle-view";
import { AntDesign } from "@expo/vector-icons";
import { ButtonDetail } from "./animal-detail.screen";
import { SafeArea } from "../../../components/utility/safe-area.component";
import { SearchAnimalContext } from "../../../services/search-animal.context";
import { Spacer } from "../../../components/spacer/spacer.component";
import { SubCategoryInfoCard } from "../components/subcategory-info-card.component";
import { ToggleContext } from "../../../services/toggle.context";
import { fetchSubCategoryData } from "../../../services/category/category.service";
import { useNavigationState } from "@react-navigation/native";

export const SubCategoryScreen = ({ route, navigation }) => {
  const [subCatgoryList, setSubCategoryList] = useState([]);
  const [isLoading, setLoading] = useState(true);
  const { performSearch, results, setInput, input } =
    useContext(SearchAnimalContext);
  const { toggle, showAccordion } = useContext(ToggleContext);
  const [toggleIcon, setToggleIcon] = useState(true);
  const { accordionCategoryItems } = useContext(AccordionCategoryItemsContext);
  const { accordionItems } = useContext(AccordionItemsContext);
  const [isSearchbarFocused, setSearchbarFocused] = useState(false);


  const previousStateRef = useRef();

  useEffect(() => {
    fetchSubCategoryData(route.params.subcategories).then((data) => {
      setSubCategoryList(
        data.animals.length > 0 ? data.animals : data.subcategories
      );
      setLoading(false);
    });
  }, [route]);

  useEffect(() => { 
    if (previousStateRef.current) {
      console.log("Previous state:", previousStateRef.current);
    }
  
    // Update ref to current state after render
     previousStateRef.current = subCatgoryList;
  }, [subCatgoryList]);

  const handleSearchChange = (text) => {
    setInput(text);
    if (text.length === 0) {
      performSearch(""); // Clear results when the input is empty
      navigation.navigate("dieren");
    } else {
      performSearch(text);
    }
  };

  const handleToggle = (itemId) => {
    toggle(itemId);
    setToggleIcon(!toggleIcon);
  };


  const updatePreviousStateRef = (currentState) => {
    if (previousStateRef.current) {
      console.log("Previous state:", previousStateRef.current);
    }   
    previousStateRef.current = currentState;
  };




  return (
    <SafeArea>
       <View style={styles.headerContainer}>
      <Button icon="arrow-left" mode="contained" onPress={updatePreviousStateRef}>
        Back to Card
      </Button>
    </View>
      
      {isLoading && (
        <LoadingContainer>
          <ActivityIndicator animating={true} color={MD2Colors.green200} />
        </LoadingContainer>
      )}
      <Searchbar
        placeholder="Zoek een dier"
        value={input}
        onFocus={() => setSearchbarFocused(true)}
        onChangeText={handleSearchChange}
        onBlur={() => setSearchbarFocused(false)}
        style={styles.searchbar}
      />
      {results.length > 0 ? (
        <AnimalDetailToggle />
      ) : (
        <CategoryList
          data={subCatgoryList.filter((item) =>
            item.name.toLowerCase().includes(input.toLowerCase())
          )}
          renderItem={({ item }) => (
            <>
            {console.log(item.id)}
        
              <Pressable
                onPress={() =>
                  navigation.navigate("groepen", { subcategories: item.id })
                }
                disabled={isLoading || (!item.animals && !item.subcategories)}
              >
                <Spacer>
                  <SubCategoryInfoCard subcategories={item} />
                </Spacer>
              </Pressable>
              <View>
                {(item.subcategories || !item.animals) && (
                  <ButtonDetail onPress={() => handleToggle(item.id)}>
                    <AntDesign
                      name={toggleIcon ? "downcircle" : "upcircle"}
                      size={19}
                      color="green"
                    />
                  </ButtonDetail>
                )}
              </View>
              {item.subcategories &&
                item.animals &&
                showAccordion.includes(item.id) &&
                accordionCategoryItems(item)}
              {(!item.animals || !item.subcategories) &&
                showAccordion.includes(item.id) &&
                accordionItems(item)}
            </>
          )}
          keyExtractor={(item) => item.id}
        />
      )}
    </SafeArea>
  );
};

const styles = StyleSheet.create({
  searchbar: {
    marginBottom: 10,
    borderRadius: 0,
  },
});

Question: how to navigate with the back button to the previous card items?