I want to catch the moment the data of fullcalendar is added

I succeeded in putting data into fullcalendar. So I tried to put the api at the point where data is added, but I can’t catch this moment….

Chat gpt tells me to put an api in handleDrop, but no console is displayed when dragging and dropping table data.

The weird spot is that when I draggable=”true” and any other letter or element I don’t specify @drop=”handleDrop” the console fires. Conflict with initializeDraggable?.

There seems to be a lot of unnecessary parts in my code, but I don’t know where to modify to send api the moment it is added to the calendar.

 <template>
  <div class="bom">
    <div class="bomTable-processList">
      <div>
        <table>
          <thead>
            <tr>
              <th colspan="6">BOM 관리</th>
            </tr>
            
            <tr v-if="bomDatas.length > 0">
              <th colspan="3">미완 <input type="radio" id="done" value="Undone" aria-label="Undone" name="bom" v-model="bomDatas[0].state" /></th>
              <th colspan="3">작성중 <input type="radio" id="editting" value="Editting" aria-label="Editting" name="bom" v-model="bomDatas[0].state" /></th>
              <th colspan="3">작성완료 <input type="radio" id="done" value="Done" aria-label="Done" name="bom" v-model="bomDatas[0].state" /></th>
              <th colspan=""><button>완료</button></th>
            </tr>
          </thead>
          <tbody id="external-events">
            <tr
              class="fc-event"
              v-for="(bomData, index) in getBomData"
              :key="index"
              draggable="true"
              @drop="handleDrop"
              @dragstart="handleDragStart($event, bomData)"
            >
              <td v-for="(process, pIndex) in bomData.process" :key="pIndex">{{ process }}</td>
              <td>{{ bomData.process_order }}</td>
              <td class="minusBtn">
                <button @click="deleteBom(bomDatas[index])">-</button>
              </td>
              <td class="upBtn">
                <button @click="moveRowUp(bomData, index)">▲</button>
              </td>
              <td class="downBtn">
                <button @click="moveRowDown(bomData, index)">▼</button>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
      <processList />
    </div>
    <equipmentList />
    <div class="full">
      <div id="external-events"></div>
      <div id="calendar-container" @dragover="handleDragOver">
        <FullCalendar
          class="demo-app-calendar"
          ref="fullCalendar"
          :options="calendarOptions"
          :editable="true"
          :events="calendarEvents"
          @eventClick="handleEventClick"
        />
      </div>
    </div>
  </div>
</template>

<script lang="js">
import processList from '@/components/detail/processList.vue'
import equipmentList from '@/components/detail/equipmentList.vue'

import { mapGetters } from 'vuex'

import FullCalendar from '@fullcalendar/vue'
import dayGridPlugin from '@fullcalendar/daygrid'
import interactionPlugin, { Draggable } from '@fullcalendar/interaction'
import resourceTimelinePlugin from '@fullcalendar/resource-timeline'

export default {
  components: {
    FullCalendar,
    processList,
    equipmentList,
  },
  data() {
    return {
      draggedData: null,
      calendarOptions: {
        schedulerLicenseKey: 'CC-Attribution-NonCommercial-NoDerivatives',
        plugins: [dayGridPlugin, interactionPlugin, resourceTimelinePlugin],
        initialView: 'dayGrid1',
        slotDuration: '24:00:00',
        resources: [],
        events: [],
        height: 600,
        headerToolbar: {
          left: 'prev,next today',
          center: 'title',
          right: 'dayGrid1,dayGrid2',
        },
        views: {
          dayGrid1: {
            type: 'resourceTimelineDay',
            duration: { days: 30 },
            buttonText: '15',
          },
          dayGrid2: {
            type: 'resourceTimelineDay',
            duration: { days: 60 },
            buttonText: '30',
          },
        },
        dayHeaderFormat: {
          weekday: 'short',
          month: 'numeric',
          day: 'numeric',
          omitCommas: true,
        },
        editable: true,
        droppable: true,
        eventResizableFromStart: true,
        eventDidMount: this.handleEventMount,
      },
      removeAfterDrop: false,
      calendarEvents: [],
    }
  },
  watch: {
    facilityDatas: {
      deep: true,
      handler() {
        this.calendarOptions.resources = this.facilityDatas.map((facility, index) => ({
          id: index.toString(),
          title: facility.facility_name,
        }))
      },
    },
  },
  updated() {
    this.$nextTick(function () {
      this.initializeDraggable();
    });
  },
  computed: {
    ...mapGetters(['getBomData', 'getProductUnitData', 'getFacilityData', 'getProductAmount', 'processDataNull']),
    facilityDatas: {
      get() {
        return this.getFacilityData
      },
      set(value) {
        const updatedValue = value.map((item) => ({
          ...item,
        }))
        this.$store.commit('setFacilityData', updatedValue)
      },
    },
    bomDatas: {
      get() {
        return this.$store.getters.getBomData;
      },
      set(value) {
        const updatedValue = value.map((item) => ({
          ...item,
        }))
        this.$store.commit('setBomData', updatedValue)
      },
    },
    productUnit() {
      return this.getProductUnitData
    },
    processDataIsNull() {
      return this.$store.getters.processDataNull;
    },
  },
  async mounted() {
    const payload = {
      product_unit: this.productUnit,
    }
    await this.$store.dispatch('getBom', payload)
    this.bomDatas = this.getBomData ? [...this.getBomData] : []

    this.calendarOptions.resources = this.facilityDatas.map((facility, index) => ({
      id: index.toString(),
      title: facility.facility_name,
    }))

    this.fullCalendar = this.$refs.fullCalendar.$refs.calendar
  },
  methods: {
    async moveRowUp(bomData, index) {
      if (index > 0) {
        [this.bomDatas[index], this.bomDatas[index - 1]] = [
          this.bomDatas[index - 1],
          this.bomDatas[index],
        ];
        this.bomDatas.forEach((data, i) => {
          data.process_order = i + 1;
        });
        await this.updateBomData();
      }
    },

    async moveRowDown(bomData, index) {
      if (index < this.bomDatas.length - 1) {
        [this.bomDatas[index], this.bomDatas[index + 1]] = [
          this.bomDatas[index + 1],
          this.bomDatas[index],
        ];
        this.bomDatas.forEach((data, i) => {
          data.process_order = i + 1;
        });
        await this.updateBomData();
      }
    },

    async updateBomData() {
      const payload = {
        product_unit: this.productUnit,
        process_names: this.bomDatas.map((data) => data.process),
      }
      await this.$store.dispatch('putBom', payload);
    },

    async deleteBom(bomData) {
      console.log(bomData)
      if (window.confirm('정말로 삭제하시겠습니까?')) {
        await this.$store.dispatch('deleteBom', {
          product_unit: bomData.product_unit,
          process_order: bomData.process_order,
          productAmount: this.getProductAmount,
        });
        const payload = {
          product_unit: this.productUnit,
        }
        await this.$store.dispatch('getBom', payload)
      }
    },
    handleEventClick(info) {
      if (confirm('삭제하시겠습니까?')) {
        info.event.remove()
        const index = this.calendarEvents.findIndex((event) => event.id === info.event.id)
        if (index !== -1) {
          this.calendarEvents.splice(index, 1)
        }
      }
    },
    handleEventMount(info) {
      const eventEl = info.el
      eventEl.addEventListener('dblclick', () => {
        this.handleEventClick(info)
      })
    },

    handleDragStart(event, bomData) {
      console.log('handleDragStart')

      if (bomData) {
        this.draggedData = {
          product_unit: bomData.product_unit,
          process_name: bomData.process,
          productAmount: this.getProductAmount,
        }
      } else {
        console.error('bomData is undefined or null')
      }
    },

    async handleDrop(event) {
      console.log('handleDrop')

      const dragData = this.draggedData
      this.draggedData = null

      if (dragData) {
        console.log('drop')

        const dateClickedArg = {
          date: this.fullCalendar.getApi().getDate(),
          allDay: true,
        }

        const facilityName = event.currentTarget.dataset.resourceId;

        const newEvent = {
          title: `${dragData.product_unit} - ${dragData.process} - ${this.getProductAmount}`,
          start: dateClickedArg.date,
          allDay: dateClickedArg.allDay,
        }

        this.calendarEvents.push(newEvent)

        if (this.removeAfterDrop) {
          const index = this.bomDatas.findIndex((data) => data === dragData)
          if (index !== -1) {
            this.bomDatas.splice(index, 1)
          }
        }
        const payload = {
          title: `${dragData.product_unit} - ${dragData.process} - ${this.getProductAmount}`,
          start: dateClickedArg.date,
          end_date: dateClickedArg.date,
          facility_name: facilityName,
        }
        console.log(facilityName)
        await this.$store.dispatch('postBom', payload)
      }
    },
    initializeDraggable() {
      console.log('initializeDraggable')

      const containerEl = document.getElementById('external-events')
      if (containerEl) {
        const eventElements = containerEl.getElementsByClassName('fc-event')
        Array.from(eventElements).forEach((eventEl, index) => {
          if (eventEl.classList.contains('draggable-initialized')) {
            return;
          }
          let draggableInstance = null;

          const createDraggable = () => {
            if (draggableInstance) {
              draggableInstance.destroy();
            }

            draggableInstance = new Draggable(eventEl, {
              eventData: () => {
                const bomData = this.bomDatas[index]
                return {
                  title: `${bomData.product_unit} - ${bomData.process} -${this.getProductAmount}`,
                }
              },
            });

            eventEl.addEventListener('dragstart', (event) => {
              const bomData = this.bomDatas[index]
              const dragData = {
                product_unit: bomData.product_unit,
                process_name: bomData.process_name,
                productAmount: this.getProductAmount,
              }
              event.dataTransfer.setData('text', JSON.stringify(bomData))
              this.draggedData = dragData
            });

            eventEl.removeEventListener('dragstart', createDraggable);
            eventEl.removeEventListener('mouseover', createDraggable);
          };

          createDraggable();

          eventEl.addEventListener('mouseover', () => {
            createDraggable();
          });
          eventEl.classList.add('draggable-initialized');
        });

        const calendarContainerEl = document.getElementById('calendar-container')
        if (calendarContainerEl) {
          calendarContainerEl.addEventListener('drop', this.handleDrop)
          calendarContainerEl.addEventListener('dragover', this.handleDragOver)
        }
      }
    },
    handleDragOver(event) {
      console.log('handleDragOver')

      event.preventDefault()
    },
  },
}
</script>

how to connect google analytics 4 in google apps script?

Previously, my google apps script used universal analytics and dispatched events from the client side.

Connection example:

(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-XXXX-Y', 'auto');
ga('send', 'event')

Now i need to upgrade to GA4 and i changed my code to this

<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXX"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'G-XXXXXXXXX');

  gtag('event', 'Name', {
   'event_category': 'Category'
 });
</script>

But it doesn’t work at all. It is possible that Data Streams, which was automatically applied from the UA account, are incorrectly specified in the Google Analytics 4 account settings.

Optimization of a global click counter widget, setinterval issue

A button on my website, when clicked, calls AJAX to increment a database value by 1. The result is shown beside the button and works as expected. I decided to incorporate a setInterval refresh on part of the code; naturally this is the part that’s causing some issues.

I’m not sure how big of an issue this is, but when I’m browsing the page with the Element Inspector I get thousands of errors–all the same error:

GET [my website] net::ERR_INSUFFICIENT_RESOURCES

It also seems like while this implementation does work part of the time the way I would expect it to, it breaks pretty quickly when I browse my site on my phone to test how it performs in real-time.

I think this might be because of the interval request:

<script>
        $(document).ready(function() {
        $("#clickButton").click(function() {
            $.ajax({
                url: "update_click_count.php",
                type: "POST",
                success: function(response) {
                    $("#count").text(response);
                }
            });
        });

        // Fetch initial click count on page load
        setInterval(function(){
            $.ajax({
                url: "get_click_count.php",
                type: "GET",
                success: function(response) {
                    $("#count").text(response);
                }
            }, 2000);
        });
        });
</script>

Is there a better way I should set this up, or is this the best possible way to do it? If I remove the interval function, the number of clicks only gets updated upon a page refresh, and I want it to update in real time, so people can see it go up no matter where they are in the world.

Get repository in a custom validator class in Nest.js and TypeORM

I am trying to make a custom decorator validator using class-validator in a Nest.JS project.

This is the code of the decorator

import { InjectRepository } from '@nestjs/typeorm';
import {
  registerDecorator,
  ValidationOptions,
  ValidatorConstraint,
  ValidatorConstraintInterface,
  ValidationArguments,
} from 'class-validator';
import { Repository } from 'typeorm';
import { Parking } from '../entities/parking.entity';

@ValidatorConstraint({ async: true })
export class UniqueNameConstraint implements ValidatorConstraintInterface {
  constructor(
    @InjectRepository(Parking) private parkingRepository: Repository<Parking>,
  ) {}

  validate(name: any, args: ValidationArguments) {
    // This line is my problem, the repository is not initialized, it's null.
    const parkingLoader = this.parkingRepository.findOne({ where: { name } });

    return parkingLoader.then((parking) => {
      if (parking) return false;
      return true;
    });
  }
}

export function UniqueName(validationOptions?: ValidationOptions) {
  return function (object: object, propertyName: string) {
    registerDecorator({
      target: object.constructor,
      propertyName: propertyName,
      options: validationOptions,
      constraints: [],
      validator: UniqueNameConstraint,
    });
  };
}

Now, I have the following DTO:

@InputType()
export class CreateEntityInput {
  @UniqueName({ message: 'The name already exists' })
  @Field(() => String, { description: 'Name of the entity' })
  name: string;
}

And this entity:

@Entity()
@ObjectType()
export class Entity {
    @Column()
    @Field(() => String, { description: 'Name of the entity' })
    name: string;
}

All I would like to know is how to get the repository inside the validator class? how to retrieve data or make a SQL call using typeORM?

The repository is always null in this code.

I’m guessing it is because it’s outside Nest.js container or something like that.

I need some guidance on this topic.

Since the conection has already been defined in the app.module.ts like this:

const typeOrm = TypeOrmModule.forRoot({
  type: 'postgres',
  host: 'database',
  port: 5432,
  username: 'postgres',
  password: 'postgres',
  database: 'postgres',
  entities: ['dist/**/*.entity{.ts,.js}'],
  synchronize: true,
});

I would really like to reuse it, but if there is no way to do it, at least I would like to know how to query to the database using typeORM from the validator class.

How to make a html table returned by functions in flask show up on the html element with ajax?

I am working on a website to give information about the most active bioassays for selected dataset of compounds. As a result, I use flask to return a html table and using ajax to show the corresponding table of bioassays and makes it changes with the dataset selected in another card:

<div class="col-6">
            <div class="card shadow p-3 mb-5 bg-white rounded" id="dataset-card">
              <div class="card-body">
                  <h3>Endpoint distribution</h3>

                  <label for="endpoint-selection">Select endpoint:</label>
                  <select class="form-control" id="endpoint-selection">
                    {% for endpoint in endpoints %}
                        <option value="{{ endpoint.Endpoint }}"> {{ ' %s (%s) ' % (endpoint.Endpoint, endpoint.Dataset)}}</option>
                    {% endfor %}
                  </select>

              <div id='endpoint-histogram' class='chart'”></div>
              </div>
            </div>
          </div>
        </div>

The block I want the table to be appended to is:

<div class="row">
          <div class="col-sm-12">
            <div class="card shadow p-3 mb-5 bg-white rounded" id="dataset-card">
              <div class="card-body">
                  <h3>Top 20 Bioassays</h3>
                  <div id='bioassay-table' class='table-stripped'”>

                  </div>

              </div>
            </div>
          </div>
        </div>

The function in flask:

def get_bioprofile_data():
    endpoint_selection = request.args.get("endpointSelection", None)
    ep = TOXICITY_ENDPOINT_INFO.set_index('Endpoint').loc[endpoint_selection].to_dict()
    dataset = ep['Dataset']

    def confusion_matrix(df, activity_class, dataset_name):
        """ this function calculates the confusion matrix for an assay, toxicity pair """
        df[activity_class] = pd.to_numeric(df[activity_class], errors='coerce')
        df = df[df[activity_class].notnull()]

        tps = ((df[activity_class] == 1) & (df.Activity_Transformed == 1)).sum()
        fps = ((df[activity_class] == 0) & (df.Activity_Transformed == 1)).sum()
        tns = ((df[activity_class] == 0) & (df.Activity_Transformed == 0)).sum()
        fns = ((df[activity_class] == 1) & (df.Activity_Transformed == 0)).sum()

        return tps, fps, tns, fns

    bioprofile = pd.read_csv(os.path.join(config.Config.BIOPROFILE_DIR, f"{dataset}+{endpoint_selection}.csv"))
    med = (
        bioprofile[['Master-ID', endpoint_selection]]
        .drop_duplicates()
        [endpoint_selection]
        .median()
    )
    bioprofile['activity'] = bioprofile[endpoint_selection].copy()
    if dataset in ['LD50_curated']:
        bioprofile.loc[bioprofile[endpoint_selection] < med, 'activity'] = 1
        bioprofile.loc[bioprofile[endpoint_selection] >= med, 'activity'] = 0
    else:
        bioprofile.loc[bioprofile[endpoint_selection] < med, 'activity'] = 0
        bioprofile.loc[bioprofile[endpoint_selection] >= med, 'activity'] = 1

    matrix = (
        bioprofile
        .groupby('AID')
        .apply(lambda x: confusion_matrix(x, endpoint_selection, dataset))
        .apply(pd.Series)
        .set_axis(['TP', 'FP', 'TN', 'FN'], axis=1)
        .reset_index()
        .sort_values('TP', ascending=False)
    )
    matrix['PPV'] = matrix.TP / (matrix.TP + matrix.FP)
    matrix['Sensitivity'] = matrix.TP / (matrix.TP + matrix.FN)
    bioprofile = pd.merge(matrix, bioprofile, on='AID', how='inner')

    PCA_DF = make_query('select [Master-ID], PCA1, PCA2, PCA3'
                        ' from chemical_space')

    CID_DF = make_query('select [Master-ID], [CID]'
                        ' from cid_lookup')

    pca = PCA_DF.merge(CID_DF, on='Master-ID', how='inner').join(
        bioprofile[['CID', 'activity']].drop_duplicates().set_index('CID'))
    pca['CIDs'] = pca.index
    pca = pd.merge(pca, bioprofile, on='Master-ID', how='inner')

    bio_info = pd.read_table(config.Config.BIOASSAYS)
    biodict = dict(zip(bio_info['AID'], bio_info['BioAssay Name']))
    pca['BioAssay Name'] = pca['AID'].map(biodict)

    table = pca.groupby(['AID', 'BioAssay Name'])['Activity_Transformed'] 
        .value_counts() 
        .unstack(fill_value=0) 
        .rename(columns={-1.0: 'Inactive', 0.0: 'Inconclusive', 1.0: 'Active'})
    table['Active rate'] = table['Active'] / (table['Active'] + table['Inactive'])
    table = pd.DataFrame(table.to_records())
    top_assays = table.sort_values(by=['Active rate'], ascending=False).head(20).to_html()

    return top_assays

The ajax module is:

var BioAssays;

      $.ajax('/api/tox-bioprofile',
          {
              data: {'endpointSelection': "{{ endpoints[0].Endpoint }}"},
              timeout: 2000,
              beforeSend: function () {
                  $('#bioassay-table').append('<div id= "load">Loading...</div>');
              },
              complete: function () {
                  $('#load').remove();
              },
              success: function (data) {
                  const $table = $("#bioassay-table");
                  const bioassays = data
                  console.log($table);
                  $table.append(bioassays);
              },
              fail: function () {
                  $('#load').remove();
                  alert("Sorry, please try again!");
              },
          }
      )

      $("#endpoint-selection").on("change", function() {
          var selectedText = this.value;
          $.ajax('/api/tox-bioprofile',
          {
              data: {'endpointSelection': selectedText },
              timeout:2000,
              beforeSend: function(){
                  $('#load').append('<div id="load">Loading...</div>');
              },
              complete: function(){
                  $('#load').remove();
              },
              success: function (data) {
                  const $table = $("#bioassay-table");
                  const bioassays = data
                  console.log($table);
                  $table.append(bioassays);
              },
              fail: function(){
                  alert("Sorry, please try again!")
                  $('#load').remove();
                             },
          }
          )

However, when I tried to append the table to the block it didn’t work correctly: Both of the loading notification and the table didn’t show up.

I have already tested the function module; it returns a html table correctly like this:

<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>AID</th>
      <th>BioAssay Name</th>
      <th>Inactive</th>
      <th>Inconclusive</th>
      <th>Active</th>
      <th>Active rate</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>625202</td>
      <td>DRUGMATRIX: Alpha-2B adrenergic receptor radioligand binding (ligand: Rauwolscine)</td>
      <td>0</td>
      <td>1555</td>
      <td>294</td>
      <td>1.0</td>
    </tr>
    <tr>
      <th>1</th>
      <td>1345284</td>
      <td>Human COX-1  (Cyclooxygenase)</td>
      <td>0</td>
      <td>0</td>
      <td>96</td>
      <td>1.0</td>
    </tr>
    <tr>
      <th>2</th>
      <td>1345783</td>
      <td>Rat D2 receptor (Dopamine receptors)</td>
      <td>0</td>
      <td>0</td>
      <td>44</td>
      <td>1.0</td>
    </tr>
    <tr>
      <th>3</th>
      <td>1345718</td>
      <td>Human D1 receptor (Dopamine receptors)</td>
      <td>0</td>
      <td>0</td>
      <td>55</td>
      <td>1.0</td>
    </tr>
    <tr>
      <th>4</th>
      <td>1345615</td>
      <td>Human 5-HT1A receptor (5-Hydroxytryptamine receptors)</td>
      <td>0</td>
      <td>0</td>
      <td>77</td>
      <td>1.0</td>
    </tr>
    <tr>
      <th>5</th>
      <td>1345543</td>
      <td>Human M5 receptor (Acetylcholine receptors (muscarinic))</td>
      <td>0</td>
      <td>0</td>
      <td>44</td>
      <td>1.0</td>
    </tr>
    <tr>
      <th>6</th>
      <td>1345465</td>
      <td>Human M4 receptor (Acetylcholine receptors (muscarinic))</td>
      <td>0</td>
      <td>0</td>
      <td>59</td>
      <td>1.0</td>
    </tr>
    <tr>
      <th>7</th>
      <td>1345364</td>
      <td>Rat M2 receptor (Acetylcholine receptors (muscarinic))</td>
      <td>0</td>
      <td>0</td>
      <td>17</td>
      <td>1.0</td>
    </tr>
    <tr>
      <th>8</th>
      <td>1345343</td>
      <td>Human M3 receptor (Acetylcholine receptors (muscarinic))</td>
      <td>0</td>
      <td>0</td>
      <td>68</td>
      <td>1.0</td>
    </tr>
    <tr>
      <th>9</th>
      <td>1345326</td>
      <td>Human M2 receptor (Acetylcholine receptors (muscarinic))</td>
      <td>0</td>
      <td>0</td>
      <td>71</td>
      <td>1.0</td>
    </tr>
    <tr>
      <th>10</th>
      <td>1345291</td>
      <td>Human 5-HT7 receptor (5-Hydroxytryptamine receptors)</td>
      <td>0</td>
      <td>0</td>
      <td>59</td>
      <td>1.0</td>
    </tr>
    <tr>
      <th>11</th>
      <td>1345286</td>
      <td>Human M1 receptor (Acetylcholine receptors (muscarinic))</td>
      <td>0</td>
      <td>0</td>
      <td>71</td>
      <td>1.0</td>
    </tr>
    <tr>
      <th>12</th>
      <td>1345235</td>
      <td>Rat 5-HT7 receptor (5-Hydroxytryptamine receptors)</td>
      <td>0</td>
      <td>0</td>
      <td>97</td>
      <td>1.0</td>
    </tr>
    <tr>
      <th>13</th>
      <td>479369</td>
      <td>Inhibition of human placental microsome CYP19</td>
      <td>0</td>
      <td>0</td>
      <td>36</td>
      <td>1.0</td>
    </tr>
    <tr>
      <th>14</th>
      <td>488784</td>
      <td>Single concentration confirmation of inhibitors of NALP3 in yeast using a Caspase-1-ASC counter screen</td>
      <td>0</td>
      <td>0</td>
      <td>4</td>
      <td>1.0</td>
    </tr>
    <tr>
      <th>15</th>
      <td>488794</td>
      <td>Single concentration confirmation of uHTS for the identification of inhibitors of NALP3 in yeast using a luminescent assay - retest</td>
      <td>0</td>
      <td>0</td>
      <td>4</td>
      <td>1.0</td>
    </tr>
    <tr>
      <th>16</th>
      <td>1345215</td>
      <td>Mouse 5-HT7 receptor (5-Hydroxytryptamine receptors)</td>
      <td>0</td>
      <td>0</td>
      <td>55</td>
      <td>1.0</td>
    </tr>
    <tr>
      <th>17</th>
      <td>1345206</td>
      <td>Human COX-2  (Cyclooxygenase)</td>
      <td>0</td>
      <td>0</td>
      <td>102</td>
      <td>1.0</td>
    </tr>
    <tr>
      <th>18</th>
      <td>1345189</td>
      <td>Rat M1 receptor (Acetylcholine receptors (muscarinic))</td>
      <td>0</td>
      <td>0</td>
      <td>38</td>
      <td>1.0</td>
    </tr>
    <tr>
      <th>19</th>
      <td>1345181</td>
      <td>Human Plasma membrane monoamine transporter (SLC29 family)</td>
      <td>0</td>
      <td>0</td>
      <td>43</td>
      <td>1.0</td>
    </tr>
  </tbody>
</table>

The question is why it didn’t show up.

jquery ajax call inside the bootstrap modal

I am using bootstrap 3.3.6 and i have the modal dialog code opens like this

<div id="myModalPositions" class="modal fade">
<div class="modal-dialog">
    <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                <h4 class="modal-title">ACT</h4>
            </div>
            <div class="modal-body">
                <p>Loading...</p>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
            </div>
    </div>
</div>

<script type="text/javascript">
$('.openStandings').on('click', function(e){
  e.preventDefault();
  $('#myModalPositions').modal('show').find('.modal-body').load($(this).attr('data-href'));
});
</script>   

inside the myModalPositions, the data-href loads a file from the server which i am doing

so i added a code inside the data-href = url where i have the form and submit and added the ajax code inside that data-href file,

every time i am trying to submit, it is closing my modal dialog

This is the ode inside the data-href url

<form name="form1" id="form1">
<input type="text" name="name" id="name">
<button type="submit" class="btn btn-primary updateData" data-dismiss="modal">Proceed</button>  
</form>
<script type="text/javascript" src="../jquery/jquery-2.1.0.js"></script>
<script type="text/javascript">
    $("#form1").submit(function (event) {
        event.preventDefault();
        var formData = $(this).serialize();
        $.ajax({
          type: "POST",
          url: "proceed.cfm",
          data: formData
        }).done(function (data) {
          console.log(data);
        });
    });
</script>   

what i am doing wrong here

Discord.js cancellation of modal cause crashes

I use the following method to wait for the modal reply after executing the slash command.

        await interaction.showModal(submissionValidateModal);

        const modalReply = await interaction.awaitModalSubmit({
            time: 60000,
            filter: i => i.user.id === interaction.user.id,
        }).catch(error => {
            console.log(error)
            return null;
        })

        // Handling Stuff

        modalReply.reply({ embeds: [requestedSentEmbed], ephemeral: true });

However, if the user execute the command, and the bot will be waiting for the modal submit event. The await would not be cancelled even if the user click cancel in this situation. When the user quickly execute the command again, and submit with the modal, it will eventually causing the error: Interaction has already been acknowledged. I believe this happens because there is more than 1 collector waiting for the modal submit, when the modal is submitted, it will cause the bot attempting to reply a more than once.

Anyone have clues on this issue?

Lexical Declarations in Javascript for loop initialization block

In the mdn docs it gives an example in which functions are initialized in the for loop initialization block

for (
  let i = 0, getI = () => i, incrementI = () => i++;
  getI() < 3;
  incrementI()
) {
  console.log(i);
}
// Logs 0, 0, 0

It gives the following explanation of why this occurs:

This logs “0, 0, 0”, because the i variable in each loop evaluation is actually a separate variable, but getI and incrementI both read and write the initial binding of i, not what was subsequently declared.

For each iteration we get a new i in the for loop body. The i variable in the initialization block is also in the scope of the for loop body.

I am hoping someone can explain this a bit better than what mdn did, I am having a bit of a hard time grasping what is going on here since there is a closure here, the i variable belongs to the scope of the for loop body, and when I add a debugger statement to getI or incrementI everything looks as one might expect, just inside the for loop body it doesn’t seem to see it and it logs 0 each iteration.

Problem with adding and removing with lastElementChild after fetching associative arrays from database

I want to show previously entered data by the user in the input fields so that the user can modify it, add more sections and remove them, so I’m getting the data from the database using the fetch_assoc() function in a while loop with the divs inside. I’m trying to append more sections after the last iteration of the while loop with an Add button and remove the last appended section with a remove button but if there’s two or more rows in the db the add button only appends after the first section and the remove button deletes the first one.

HTML

<script> var r=0;</script>
    <h2>Music</h2>
    <?php
        $query = "SELECT mu.id, alb.album, alb.song 
                  FROM music AS mu
                  INNER JOIN albums AS alb ON mu.id = alb.music_id
                  WHERE alb.music_id = '{$_SESSION['idmu']}';";
        $result = $mysqli->query($query);
        
        while ($row=$result->fetch_assoc()) {
    ?>
    <div id="container">
        <div id="mainsection">
    
        <h3>Album</h3>
        <input type="text" name="album[]" id="album" value="<?php echo $row['album'];?>">
        <br>
        <h3>Song</h3>
        <input type="text" name="song[]" id="song" value="<?php echo $row['song'];?>">
        <script> r++;</script> 
        <br><br>
        
        </div>
    </div>
    <?php
        }
    ?>
    
    <button type="button" id="addbtn">Add</button>
    <button type="button" id="removebtn">Remove</button>

    <script>
        addbtn.addEventListener("click", function(e) {
        var container = document.getElementById("container");
        var section = document.getElementById("mainsection");   
        container.appendChild(section.cloneNode(true));
        r++;
        });

        removebtn.addEventListener("click", function(e) {
        var section = document.getElementById("mainsection");
        if(r > 1) {
        r--; 
        var sec=document.getElementById("mainsection"); 
        var parentDiv = sec.parentNode; 
        parentDiv.removeChild(parentDiv.lastElementChild); 
        }
        else { //so it doesn't remove the section if there's only 1
        }
        });  
    </script>

Tried appendChild inside the while loop but it only creates duplicates. Also added a variable “r” so I could prevent it from deleting the first section if that’s the only one remaining. I was trying to use pure JS only but jQuery is fine too.

jsPDF addImage() PNG images not shown

I am using jsPDF to render some images, there are some GIF, PNG, JPEG images, and I just use the image src link.

All other image are fine and can be loaded and displayed well, but some images just displayed blank, and I observed they are PNG file. Although they are blank, the file size can tell the image is already embeded.

I inspected inside the addImage function and see all images (including those PNG img) binary are loaded correctly on this line before write to file: https://github.com/parallax/jsPDF/blob/master/src/modules/addimage.js#L855

enter image description here

so that is not an image loading problem, it is the jsPDF not render correctly.

This is the code I used to add image:

doc.addImage({
    imageData: srcLink,
    format: "JPEG",
    x: x,
    y: y,
    width: w,
    height: h,
    compression: "SLOW",
});

If I change format to PNG (for all image), jsPDF failed with error say invalid PNG format for some images.

So I wrote function to parse image format and use correct format for all different image, but also have the same error invalid PNG format for some images.

So I guess JPEG is good for all.

Don’t know why???

difference between patch and put in the request method

I just want to know the difference between them,i tring to find out the difference in the official website of JS ,Because most of the information on the Internet is a bit too repetitive, and I try my best to explore the differences between them, but it is still not enough, so I send all of them here to see what everyone thinks about patch and put

Number of items in array of contacts from People.People.Connections.list() doesn’t match totalItems, doesn’t contain all contacts [duplicate]

I’m working Google Apps Script. I can obtain all of my Google Contacts using the People API method People.People.Connections.list(). The response body contains an array of People called Connections, and an integer representing the total number of contacts returned, called totalItems (among other things).

When I run the following test,

function getConnections() {
  try {
    // Get the list of connections/contacts of user's profile
    var people = People.People.Connections.list('people/me', {
      personFields: 'names'
    });

    //Display the whole list
    Logger.log('Connections: %s', JSON.stringify(people, null, 2));
  } catch (err) {
    Logger.log('Failed to get the connection with an error %s', err.message);
  }

  Logger.log(`totalItems: ${people.totalItems}`);
  Logger.log(`length of people.connections: ${people.connections.length}`);

  //Output the names of all the People in people.connections.
  for(i = 0; i < people.connections.length ;i++){
    if(people.connections[i] && people.connections[i].names){
      Logger.log(i + " " + people.connections[i].names[0].displayName);
    }
    else {Logger.log("Something wrong with contact?")}
  }
}

Logger outputs:

Info totalItems: 155

Info length of people.connections: 100

The for loop outputs the connection’s names just fine, those that exist in the array anyway.
Does anyone have any insight into this? Thank you in advance.

Move one ref from child to parent using forwardRef and useImperativeHandle while have other ref used in child component

I would like currRef to access dom from MyInput component and inputRef to access dom from App component. So I used useImperativeHandle with forwardRef, but I get null value for both currRef and inputRef. What am I doing wrong?

import React from "react";
import { forwardRef, useRef, useImperativeHandle  } from 'react';
import "./style.css";

export default function App() {
  const childRef = useRef(null);

  function handleClick() {
    console.log('ref ', childRef);
    childRef.current.inputRef.current.focus();
  }

  return (
    <form>
      <MyInput label="Enter your name:" ref={childRef} />
      <button type="button" onClick={handleClick}>
        Edit
      </button>
    </form>
  );
}

const MyInput = forwardRef(function MyInput(props, ref) {
  const { label, ...otherProps } = props;
  const inputRef = useRef(null);
  const currRef = useRef(null);

  console.log('currRef ', currRef.current)

  useImperativeHandle(ref, () => ({
    inputRef,
  }));
  
  return (
    <label>
      {label}
      <input {...otherProps} ref={currRef} />
    </label>
  );
});