Alpine.js data update not reflected in the frontend

I’m creating a small app using Alpine.js in Typescript, but ran into an issue with my property change not being reflected in the frontend. I want to change the property progress inside my Group instance.

When I update the progress value from within my App class, it does work fine:

import Alpine from 'alpinejs';
import Group from './group';

class App
{
    public group: Group;

    init(): void
    {
        this.group = new Group;
    }
    
    setTimeout(() => this.group.progress = 100, 2000);
}

document.addEventListener('alpine:init', () =>
{
    Alpine.data('app', () => new App);
});

Alpine.start();

However, updating the value from within my Group class doest not change the value in the frontend:

export default class Group
{
    public progress: number = 50;

    constructor()
    {
        setTimeout(() => this.progress = 100, 2000);
    }
}

I have tried messing around with Alpine.reactive which some people recommended, but this did not work either. What am I missing here?

Fancy product designer pricing options wordpress/woocommerce [closed]

I have recently been working on creating a website for my company. I will be selling drinks boards here with the option to personalize the boards. It makes a difference in the price whether the customer wants it personalized or not. So I want the customer to be able to make a choice here. I use wordpress with woocommerce. I also have the Fancy Product Designer plugin to personalize the product. I wish that if someone makes a design in the fancy product design plugin, the price will change. If the customer chooses not to click on the personalize button, he will not receive the personalized board back and the price therefore remains standard. Can anyone help me on how I can get this done?

I have already seen that there are certain plugins, but they have not yet been able to offer me the solution I am looking for. So i hope anyone can help me.

Retrieve subtree recursively JS [duplicate]

I am writing a function which takes a tree of categories and category id and returns a subtree starting the node with cpecified id. In other words I pass tree:

const tree = [
    {
        "id": "55f842fb17bb4ab2a4d13e60d17da930",
        "name": "Goods",
        "children": [
            {
                "id": "60565f3641b14220a9cc448165b7613e",
                "name": "Goods subcategory",
                "children": [
                    {
                        "id": "cb038659ec9a4bc2a76a1502e6da5bd6",
                        "name": "Goods subsubcategory",
                        "children": [
                            {
                                "id": "dfc8d2bb471c4fc0a32990abff70f07f",
                                "name": "Goods subsubsubcategory 1",
                                "children": []
                            },
                            {
                                "id": "132340bf576d4566b6132f6b0309000e",
                                "name": "Goods subsubsubcategory 2",
                                "children": []
                            }
                        ]
                    }
                ]
            }
        ]
    }
]

and id “cb038659ec9a4bc2a76a1502e6da5bd6”

and need to receive the following tree:

                        "id": "cb038659ec9a4bc2a76a1502e6da5bd6",
                        "name": "Goods subsubcategory",
                        "children": [
                            {
                                "id": "dfc8d2bb471c4fc0a32990abff70f07f",
                                "name": "Goods subsubsubcategory 1",
                                "children": []
                            },
                            {
                                "id": "132340bf576d4566b6132f6b0309000e",
                                "name": "Goods subsubsubcategory 2",
                                "children": []
                            }

I try to do this recursively, but fail.
In fact I manage to DFS my tree, but I cant return the subtree correctly. What do I do wrong? Why I can print out the subtree, but cant return it in the same if statement?
BTW: I know that forEach does not return anything.
This is my code:

const getSubTree = (tree, category) => {
    if (String(tree.id) === category){
        console.log(tree)            //It prints out the tree
        return tree                  //???Why it does not return tree
    }
    tree.children.forEach(child => {
        getSubTree(child, category)
    })
}

console.log(getSubTree(categoriesTree[0], '2'))

why is my input not registering text or capturing the value of what i am typing in?

Im working on some code thats using react hook form to capture input states and im not exactly sure why when I type into the input, specifically the one with the placeholder text of “Or search for a contact type by name…” , i dont see the input box populating with any characters, i basically type into it and it stays blank. Ive tried console.log(watch(“searchValue”)) but im just getting blank spaces in the console. Any idea whats going on here? it seems the register function in the form input isnt actually capturing the value

/* eslint-disable react-hooks/exhaustive-deps */



export default function Home() {
  const ref = useRef<HTMLDivElement>(null);
  const user = useAuthUser();
  const depts = useDepts();
  const [currentTab, setCurrentTab] = useState("My Contacts");

  const [isAllDepts, setIsAllDepts] = useState(false);
  const [selectedSchoolId, setSelectedSchoolId] = useState(user.DeptId);
  const [selectedContactType, setSelectedContactType] = useState<ContactType | null>();
  const [showModalEmplSearch, setShowModalEmplSearch] = useState(false);
  const [showModalEditContact, setShowModalEditContact] = useState(false);
  const [showModalExempt, setShowModalExempt] = useState(false);
  const [selectedContact, setSelectedContact] = useState(initContact);
  const syncContacts = useSyncContacts(selectedSchoolId);
  const contactTypes = useContactTypesAppliesTo(selectedSchoolId);

  const allContactTypes = useContactTypes();
  const contacts = useContactsByDeptType(selectedSchoolId, selectedContactType?.PkId ?? 0);
  const allContactsFromAllTypes = useContactsByDept(selectedSchoolId);
  const contactsByType = useContactsbyType(selectedContactType?.PkId ?? 0);
  const upsertContact = useUpsertContact();
  const deleteContact = useDeleteContact();
  const deleteExemption = useDeleteExemption();
  const { register, watch, reset, setValue } = useForm();
  console.log(watch("searchValue"));

  const [isHoveredContacts, setIsHoveredContacts] = useState(false);
  const [isHoveredRequested, setIsHoveredRequested] = useState(false);
  const [isHoveredLookup, setIsHoveredLookup] = useState(false);
  const [isHoveredGlobal, setIsHoveredGlobal] = useState(false);
  const [tab, setTab] = useState("");

  const handleIconMouseEnter = (e: any) => {
    const tabName = e.target.parentElement.innerText.trim(); // Get the tab name from the parent element

    if (tabName === "My Contacts") {
      setIsHoveredContacts(true);
      setTab(tabName);
    } else if (tabName === "Requested Contacts") {
      setIsHoveredRequested(true);
      setTab(tabName);
    } else if (tabName === "Contact Lookup") {
      setIsHoveredLookup(true);
      setTab(tabName);
    } else if (tabName === "Global Search") {
      setIsHoveredGlobal(true);
      setTab(tabName);
      setSelectedSchoolId(selectedSchoolId ?? user.DeptId);
    }
  };

  const handleMouseLeave = (tabName: string) => {
    if (tabName === "My Contacts") {
      setIsHoveredContacts(false);
    } else if (tabName === "Requested Contacts") {
      setIsHoveredRequested(false);
    } else if (tabName === "Contact Lookup") {
      setIsHoveredLookup(false);
    } else if (tabName === "Global Search") {
      setIsHoveredGlobal(false);
    }
  };

  useEffect(() => {
    if (currentTab === "lookup") {
      setIsAllDepts(true);
      setSelectedContactType(null);
      setSelectedSchoolId(selectedSchoolId ?? user.DeptId);
      setValue("hasIssues", false);
    } else if (currentTab === "Requested contacts") {
      setSelectedContactType(null);
      setSelectedSchoolId(selectedSchoolId ?? user.DeptId);
      setValue("hasIssues", false);
      setIsAllDepts(false);
    } else if (currentTab === "My Contacts") {
      setSelectedContactType(null);
      setSelectedSchoolId(selectedSchoolId ?? user.DeptId);
      setValue("hasIssues", false);
      setIsAllDepts(false);
      contactTypes.refetch();
    } else if (currentTab === "Global Search") {
      setIsAllDepts(true);
      setSelectedContactType(null);
      setSelectedSchoolId(selectedSchoolId ?? user.DeptId);
      setValue("hasIssues", false);
    }
  }, [currentTab]);

  // When a user first logs in, run the sync service to make sure the dept is in sync
  useEffect(() => {
    sync();
  }, []);

  // If the URL has "/issues" on first page load,
  // then automatically check the box to show contact types with issues
  useEffect(() => {
    if (window.location.pathname.includes("issues")) {
      setValue("hasIssues", true);
    }
  }, []);

  // Every time an impersonation happens, just reset the selectedSchoolId
  useEffect(() => setSelectedSchoolId(user.DeptId), [user]);

  /** Call the sync service to sync the contacts with the DB */
  const sync = async () => {
    await syncContacts.refetch();
    await contactTypes.refetch();
  };

  /** Handles what happens when the "View all departments" checkbox is enabled/disabled */
  const handleIsAllDeptsCheckBox = () => {
    setIsAllDepts(!isAllDepts);
    setSelectedContactType(null);
    setSelectedSchoolId(user.DeptId);
    setValue("hasIssues", false);
  };

  const deptsRequesting = [
    ...new Set(
      (isAllDepts ? allContactTypes.data : contactTypes.data)?.map((ct) => ct.Department.DeptName),
    ),
  ].sort((a, b) => (a > b ? 1 : -1));

  const filteredContactTypes = (isAllDepts ? allContactTypes.data : contactTypes.data)?.filter(
    (ct) => (watch("selectedDepts") ?? []).includes(ct.Department.DeptName),
  );

  /** Checks if the array of issues from a contact type includes one of the `statusIssues` elements */
  const checkIfStatusIssue = (issues: ContactStatus[]) => {
    for (const i of issues) if (statusIssues.includes(i)) return true;
  };

  const getContactTypes = () =>
    (!watch("selectedDepts") || watch("selectedDepts").length === 0
      ? (isAllDepts ? allContactTypes.data : contactTypes.data) ?? []
      : filteredContactTypes
    )?.filter((ct) => ct.Title.toLowerCase().includes((watch("searchValue") ?? "").toLowerCase()));

  const getAllContacts = () =>
    (watch("searchValue").length === 0
      ? allContactsFromAllTypes.data
      : allContactsFromAllTypes?.data?.filter((x) =>
          x.ContactType.Title.toLowerCase().includes((watch("searchValue") ?? "").toLowerCase()),
        )) ?? [];

  const getDepts = () =>
    (watch("searchValue").length === 0
      ? allContactsFromAllTypes.data
      : allContactsFromAllTypes?.data?.filter((x) =>
          x.ContactType.Title.toLowerCase().includes((watch("searchValue") ?? "").toLowerCase()),
        )) ?? [];

  // const getAllContacts = () =>
  //   watch("searchValue") === ""
  //     ? allContactsFromAllTypes?.data ?? []
  //     : allContactsFromAllTypes?.data?.filter((ct) =>
  //         ct.ContactEmployee.JobTitle.toLowerCase().includes(
  //           (watch("searchValue") ?? "").toLowerCase(),
  //         ),
  //       ) ?? [];

  const handleRemoveExemption = async () => {
    const path = `${Methods.Exemptions}/${selectedContactType?.PkId}/${selectedSchoolId}`;
    const exemption = await queryClient.fetchQuery<Exemption>("exemption", () => API.Get(path));
    await deleteExemption.mutateAsync(exemption.PkExemptionId ?? "");
    await toast.promise(sync(), {
      loading: "Removing exemption...",
      success: `Successfully removed the exemption for ${selectedContactType?.Title}!`,
      error: "Could not remove the exemption.",
    });
    const updatedCt = await queryClient.fetchQuery<ContactType[]>([
      `${Methods.ContactTypesAppliesToDept}/${selectedSchoolId}`,
    ]);
    setSelectedContactType(updatedCt.find((ct) => ct.PkId === selectedContactType?.PkId));
  };

  const handleAddContact = async (emp: Employee) => {
    setShowModalEmplSearch(false);
    const postData: ContactPostModel = {
      ContactTypeId: selectedContactType?.PkId ?? 0,
      DeptId: selectedSchoolId,
      ContactEmplId: emp.EmplId,
      ContactStatus: ContactStatus.Ok,
    };
    if (selectedContact.PkId) postData.PkId = selectedContact.PkId;

    await upsertContact.mutateAsync(postData);

    setSelectedContact(initContact);
    contacts.refetch();
    contactTypes.refetch();
    toast.success(
      `Successfully added ${emp.FirstName} ${emp.LastName} as a new contact for "${selectedContactType?.Title}"`,
    );
  };

  const handleDeleteContact = async (c: Contact) => {
    await deleteContact.mutateAsync(c.PkId ?? "");
    contacts.refetch();
    await toast.promise(sync(), {
      loading: "Deleting contact...",
      success: `Successfully removed ${c.ContactEmployee.FirstName} ${c.ContactEmployee.LastName} as a contact for ${selectedContactType?.Title}`,
      error: "Could not delete this contact.",
    });
  };

  function handleClick(e: any) {
    setCurrentTab(e);

    //result will be the eventKey of the tab you clicked on.

    // `homeTab` (when clicked on home tab)
    // `profileTab` (when clicked on profile tab)
    // `constactTab` (when clicked on Contact tab)
  }

  const contactsTooltip = (
    <Tooltip id="contacts-tooltip">Manage contacts for your school or department</Tooltip>
  );
  const requestedContactsTooltip = (
    <Tooltip id="requested-contacts-tooltip">
      Manage the contact types that are related to your department
    </Tooltip>
  );
  const contactLookupTooltip = (
    <Tooltip id="contact-lookup-tooltip">Lookup and export contacts</Tooltip>
  );

  return (
    <div>
      <Helmet>
        <title>Points of Contact</title>
      </Helmet>
      <p>
        <span style={{ fontWeight: "bold", fontSize: "2rem" }}>
          {selectedSchoolId &&
            `Viewing ${
              isAllDepts
                ? "All Departments"
                : getDeptName(depts.data, selectedSchoolId, user.Department)
            }`}
        </span>
      </p>

      <hr />

      <ExportContacts
        contacts={allContactsFromAllTypes.data ?? []}
        title={getDeptName(depts.data, selectedSchoolId, user.Department)}
        isEntireList
      />
      <br />
      <Tabs
        defaultActiveKey="profile"
        id="justify-tab-example"
        className="mb-3"
        style={{ marginTop: "20px" }}
        onSelect={(e) => handleClick(e)}
        activeKey={currentTab}
      >
        <Tab
          eventKey="My Contacts"
          title={
            <span style={{ position: "relative", display: "inline-block" }}>
              My Contacts
              <OverlayTrigger placement="top" overlay={contactsTooltip} show={isHoveredContacts}>
                <i
                  className="fa-solid fa-circle-info"
                  style={{ marginLeft: "10px", color: "#3870c9" }}
                  onMouseEnter={handleIconMouseEnter}
                  onMouseLeave={() => handleMouseLeave(tab)}
                />
              </OverlayTrigger>
            </span>
          }
        >
          <Row style={{ backgroundColor: "#F5F5F5", padding: 20, borderRadius: 10 }}>
            <Col md={4}>
              <div>
                <h3>My Contacts</h3>
                <div id="contact-type-filter" style={{ marginBottom: "0.5rem" }}>
                  <i style={{ color: "#727272" }}>Manage contacts for your school or department.</i>{" "}
                  <Dropdown
                    autoClose="outside"
                    style={{
                      cursor: "pointer",
                    }}
                  >
                    <Dropdown.Toggle
                      id="filter-text"
                      as="span"
                      style={{
                        paddingLeft: 8,
                        paddingRight: 8,
                      }}
                      title="More options"
                    >
                      <i className="fa-solid fa-filter p-1" />
                      Dept Filter
                    </Dropdown.Toggle>
                    <Dropdown.Menu>
                      <label style={{ padding: "2px 14px", textAlign: "center" }}>
                        Filter by the department(s) requesting these contact types
                      </label>
                      <Button
                        variant="outline-primary"
                        style={{
                          display: "flex",
                          justifyContent: "center",
                          padding: "6px 0px",
                          width: "80%",
                          margin: "0 auto",
                        }}
                        onClick={() => reset()}
                      >
                        Reset Filters
                      </Button>

                      <Dropdown.Divider />
                      <Form.Group
                        style={{
                          padding: "2px 14px",
                          width: 350,
                          maxHeight: "25rem",
                          overflowY: "scroll",
                        }}
                      >
                        {deptsRequesting.map((dept) => (
                          <Form.Check
                            key={dept}
                            label={dept}
                            value={dept}
                            {...register("selectedDepts")}
                          />
                        ))}
                      </Form.Group>
                    </Dropdown.Menu>
                  </Dropdown>
                </div>
                {!isAllDepts && (
                  <Form.Check
                    style={{ paddingLeft: "2.2rem" }}
                    label="Show Contact Types With Issues"
                    {...register("hasIssues")}
                  />
                )}
                <Form>
                  <Form.Control
                    placeholder="Or search for a contact type by name..."
                    {...register("searchValue")}
                  />
                </Form>
                <ListGroup
                  style={{
                    borderColor: "#BCBCBC",
                    height: "30rem",
                    overflow: "auto",
                    border: "1px solid #bcbcbc7d",
                    background: "white",
                    marginTop: "0.5rem",
                  }}
                >
                  {contactTypes.isLoading || allContactTypes.isLoading ? (
                    <ContactTypesLoading />
                  ) : (
                    (watch("hasIssues")
                      ? getContactTypes()?.filter(
                          (ct) =>
                            (ct.HasIssues && !ct.Issues.includes(ContactStatus.Exempted)) ||
                            (ct.Issues.includes(ContactStatus.Exempted) && ct.MinQty > 0),
                        )
                      : getContactTypes()
                    )?.map((ct) => (
                      <ListGroup.Item
                        key={ct.PkId}
                        onClick={() => {
                          setSelectedContactType(ct);
                          ref.current?.scrollIntoView({ behavior: "smooth" });
                        }}
                        active={selectedContactType?.PkId === ct.PkId}
                        style={{ border: "none" }}
                        action
                      >
                        <i
                          className={`fa-solid fa-circle-${
                            ct.HasIssues && checkIfStatusIssue(ct.Issues) ? "exclamation" : "check"
                          }`}
                          style={{
                            color: `${
                              selectedContactType === ct
                                ? "white"
                                : ct.HasIssues && checkIfStatusIssue(ct.Issues)
                                ? "#8f0a15"
                                : "green"
                            }`,
                            paddingRight: 6,
                          }}
                          title={
                            (ct.Issues ?? []).length > 0
                              ? Object.values(ContactStatusDescr).find(
                                  (c, i) =>
                                    i === ct.Issues[0] && ct.Issues[0] !== ContactStatus.Exempted,
                                )
                              : ""
                          }
                        />
                        <b>{ct.Title}</b>
                        <br />
                        <span style={{ fontSize: "0.8rem" }}>
                          Requested By: {ct.Department.DeptName}
                        </span>
                        <br />
                        {!isAllDepts && (
                          <span style={{ fontSize: "0.8rem" }}>
                            Required # of Contacts: {ct.MinQty}
                          </span>
                        )}
                        {(ct.Issues ?? [])?.at(0) === ContactStatus.Exempted && (
                          <Badge bg="warning" style={{ float: "right" }}>
                            Exempt
                          </Badge>
                        )}
                      </ListGroup.Item>
                    ))
                  )}
                </ListGroup>
              </div>
            </Col>

     

How to use d3.js to emulate spreadsheet-like keyboard navigation

I have built a webpage using HTML/JS with D3.js to allow data entry/editing. The data is output to the page as a table and there are input boxes to allow the user to update information and then send it back to the server.

What I’m looking for is a way to provide traditional keyboard navigation between rows. The columns are handled by the built-in tab order functionality, but I’d like to be able to use up and down arrow keys to go between rows. There is a data-field attribute that is used to identify the column (for feeding new values back to the server), so the idea is that pressing “up” would move the focus to the previous element in the DOM that has the same data-field value, and similarly for the down button going to the next element.

The table layout is something like this:

<table id="data-table">
  <tr>
    <th>Row 1 header</th>
    <td><input type="text" data-field="field-1" data-id="row-1" /></td>
    <td><input type="text" data-field="field-2" data-id="row-1" /></td>
    <td><input type="text" data-field="field-3" data-id="row-1" /></td>
  </tr>
  <tr>
    <th>Row 2 header</th>
    <td><input type="text" data-field="field-1" data-id="row-2" /></td>
    <td><input type="text" data-field="field-2" data-id="row-2" /></td>
    <td><input type="text" data-field="field-3" data-id="row-2" /></td>
  </tr>
  <tr>
    <th>Row 3 header</th>
    <td><input type="text" data-field="field-1" data-id="row-3" /></td>
    <td><input type="text" data-field="field-2" data-id="row-3" /></td>
    <td><input type="text" data-field="field-3" data-id="row-3" /></td>
  </tr>
</table>

Using D3.js, I’m figuring that the event handling process would be something like

d_field = d3.select('input:focus').attr('data-field'); \ alternatively use event.currentTarget
d_col = d3.selectAll('input[data-field="'+d_field+'"]');

From there, it would be checking the d_col selection to see which element refers to the same node as the d_field selection, then moving to the next or previous element and applying the focus to it. I’m just stumbling over that check and move part.

JavaScript To Combine Multiple Text Fields / Creating Consistent File Names [closed]

When reviewing stackoverflow I found a question and answer on what I am looking to include in an Install Report

Subject Combine Multiple Input Fields into One Input Field with JavaScript?

Although I am unable to have it execute.

Does all the JavaScript need to be entered?
Is there a something that needs to be turned on?
What is the color code Red, Green, Blue, Black

Can this be run from the Calculate – Custom Calculation script Edit Add or entered through Actions

Is there a something that needs to be turned on?
What is the color code Red, Green, Blue, Black

When I copied and pasted the JavaScript from
POST Combine Multiple Input Fields into One Input Field with JavaScript?

I received an error message

Your post appears to contain code that is not properly formatted as code. Please indent all code by 4 spaces using the code toolbar button or the CTRL+K keyboard shortcut. For more editing help, click the [?] toolbar icon.
`

JavaScript To Combine Multiple Text Fields / Creating Consistent File Names
Subject: Combine Multiple Input Fields into One Input Field with JavaScript?

POST:BELOW Helps but I am unable to execute
Combine Multiple Input Fields into One Input Field with Javascript?

Want to set the Pre-loader only for the HOME page using PHP

<!-- preloader -->
    <div class="art-preloader">
      <!-- preloader content -->
      <div class="art-preloader-content">
        <!-- title -->
        <h5>Loading the &nbsp <span style="color: #FFC107;">page</span> </h5>
        <!-- progressbar -->
        <div id="preloader" class="art-preloader-load"></div>
      </div>
      <!-- preloader content end -->
    </div>
    <!-- preloader end -->

I am basically using a web template made of **Bootstrap **and for my **Backend **I am using row PHP. And this is my pre-loader HTML code. Now as I have multiple pages like “Home, About, Contact, etc”. Every time I refresh any page it shows the pre-loader. But I want to show the pre-loader when only my home page is loaded. If anyone could help me to solve the problem using inner PHP code ??

I am beginner, I dont have that much idea on PHP but am trying to learn it as much as I can. Talking about the specific problem, I tried to use inner PHP code like using IF/ELSE statement to solve the problem but it didn’t work.

window.alert works after clearing cache in safari

I’m building an extension for safari.

I have window.alert in content.js. It works most of the time, but sometimes it doesn’t.
When it doesn’t work, I clear cache of safari and it starts working again.

I want to make it work all the time without clearing cache.

How can I achieve it?

I googled but I couldn’t find any related questions about this problem.

Smooth slide on details disclosure not working (using jQuery slideUp)?

I’m sure Im just missing something silly here, but I’m pulling my hair out trying to understand what’s going wrong here. I have a details disclosure section that I’m trying to use slideUp and slideDown to enable a smooth transition when a user clicks on the tab, whether they are opening or closing it. And half of it is done, it slides open fine, but it just snaps itself back shut. I added console logs to make sure nothing weird was going on, but no errors and console logs all showing fine makes this tricky to figure out. Code and Codepen below. Thanks in advance for any advice!

<div class="outreach">
<details class="outreach-tab">
  <summary class="tab-title">
    Detail Header
  </summary>
  <div class="prose max-w-none outreach-details">
    Vestibulum vitae suscipit magna, in vehicula neque. Morbi ut dolor lorem. Quisque mattis metus rhoncus massa mollis imperdiet. Sed eleifend risus metus, id suscipit nisi dictum id. Vestibulum rhoncus dui vitae nunc pellentesque, vitae pellentesque neque condimentum. 
  </div>
</details>
</div>

And the accompanying SCSS:

.resource,
.outreach {
  .outreach-tab {
    summary {
      padding: 20px;
      background: #ccdbe5;
      border-bottom: 1px solid #333333;
      cursor: pointer;
      font-size: 120%;
      font-weight: bold;
      
      text-transform: uppercase;
      position: relative;
    }

    .outreach-details {
      background: #ffffff;
      padding: 20px;
      margin-top: 10px;
      display: none; /* Hidden by default */
    }
  }
}

And then finally the JS:

jQuery(document).ready(function ($) {
  $("details").on("toggle", function () {
    const detailsElement = $(this).find(".outreach-details");

    if (this.open) {
      detailsElement.slideDown();
    } else {
      detailsElement.slideUp();
    }
  });
});

If you want to see it broken in the wild, here’s a codepen replicating the problem 🙂
https://codepen.io/jcforrester/pen/mdZjodd

How to design classes with different set of public methods [closed]

I am try to develop a configuration management tool, but stuck in designing the class diagrams.

I have primarily 2 type of configuration management.

  1. Simple – provides basic CRUD operation only
  2. Versioned – In addition to CRUD, it supports commit, rollback, etc.

I tried using strategy pattern but stuck in it as the strategies are not truly replaceable.

My question is

  • Can these can be subclasses to a base class as they have different set of public methods thus violation LSP
  • Can these be treated as different strategy, in that case also one strategy has additional behaviour than the other.

trouble with GA4 and GTM

I have a problem with GA4 and GTM, which i cant solve already for 3 days 🙁

I created a GA4 tag and event, called it “login”. It has a parameter “method” witch default value is “00000000000000000000”. i need to call this event and set “method” value to my custom (for example, “ZZZZZZZZZZZZZZZZZZZZ” – it will always be random).
Here is javascript code, which calls my event:

window.dataLayer = window.dataLayer || [];

var x = null;

x=window.dataLayer.push('js',new Date());console.log('js ');console.log(x);
x=window.dataLayer.push('config','G-*******');console.log('config ');console.log(x);

x=window.dataLayer.push('set','login',{'method':'ZZZZZZZZZZZZZZZZZZZZ'});console.log('set ');console.log(x); 
x=window.dataLayer.push({'event':'login','method':'ZZZZZZZZZZZZZZZZZZZZ'});console.log('event ');console.log(x); 

here is the result:

js false
config true
set true
event false

only the default value of “00000000000000000000” is sent to the server instead of “ZZZZZZZZZZZZZZZZZZZZ”. always!
when calling an event, a request always send default value of method

https://analytics.google.com/g/collect?v=2&tid=G-*******’&gtm=45je48r0v9193929697z89192937461za200&_p=1724944900794&gcd=13l3l3l3l1l1&npa=0&dma=0&tag_exp=0&cid=476783039.1711069035&ul=ru-ru&sr=2560×1440&uaa=x86&uab=64&uafvl=Not)A%253BBrand%3B99.0.0.0%7CGoogle% 2520Chrome%3B127.0.6533.120%7CChromium%3B127.0.6533.120&uamb=0&uam=&uap=Windows&uapv=15.0.0&uaw=0&are=1&pae=1&frm=0&pscdl=label_only_1&_s=3&sid=17249 42914&sct=18&seg=1&dl=https%3A%2F%2Fmyweb.com%2F&dt=Search&en=login&_c=1&ep.method=00000000000000000000&_et=2&tfd=3996

here is dataLayer content from DebugView:

{
0: “l”,
1: “o”,
2: “g”,
3: “i”,
4: “n”,
5: “T”,
6: “S”,
7: “Y”,
8: “V”,
9: “T”,
10: “L”,
11: “H”,
originalLocation: “https://myweb.com/index.html?” +
“gtm_debug=1724946021188”,
event: “login”,
gtm: {
uniqueEventId: 7,
start: 1724946023196,
allowlist: undefined,
blocklist: undefined,
whitelist: undefined,
blacklist: undefined
},
tagTypeBlacklist: undefined,
propertyName: “web”,
method: “ZZZZZZZZZZZZZZZZZ”
}

plz help, whats the problem? i’am newbie to GTM/GA4.

i tried to reconfigure events, tried to fix “method” to “ep.method”. also i tried to make some changes to my GA4 account (by adding custom dimensions).

x=window.dataLayer.push(‘set’,’login’,{‘method’:’ZZZZZZZZZZZZZZZZZZZZ’});console.log(‘set ‘);console.log(x);
x=window.dataLayer.push({‘event’:’login’,’method’:’ZZZZZZZZZZZZZZZZZZZZ’});console.log(‘event ‘);console.log(x);

i just need to send my own custom value of “method” parameter.

How can I use double click with javascript?

I am new to the javascript. I want to double click a button and write something to the console but the code I use doen’t work

The code here:
btnAddTask.addEventListener("dblclick",run);

I think “dblclick” event is wrong. What is the true code?
I am using Live Server to open the project. Could it be caused by that?
How can I use double clik on the buttons?

Javascript IntersectionObserver on Inactive Tab?

I tried to use IntersectionObserver to check, when an element (button) is visible.

But when i tab out, so the tab is inactive, he doesnt see it anymore. When i tab in, he sends the console.log found instantly.

Any ideas, if there is a way, to check if the button is visible

const observer = new IntersectionObserver(([entry]) => {
    if (entry.isIntersecting) {
        console.log('found')
    }, {
        root: null,
        threshold: 0.1, // set offset 0.1 means trigger if atleast 10% of element in viewport
})
observer.observe(document.querySelector(el));

I also tried MutationObserver but that cannot check if the button is in view. Just checking if there is code in background. And when its one time there, its there forever, also when its invisible than.

I just want to check if the button can be clicked right now, nothing more. But with MutationObserver he spams found, cause he found the code in background, also when the button is not in view.

I tried to search for someone with the same problem. Also tried mutationObserver but thats not the same.