write from app web to google spreedsheets

I try of a dev solution for my company and I’m stuck with API of google sheets. I trying of write a page of googlesheets and my code no run without show me any error. I will greatfull for your asist.


/* exported gapiLoaded */
/* exported gisLoaded */
/* exported handleAuthClick */
/* exported handleSignoutClick */

// TODO(developer): Set to client ID and API key from the Developer Console
const CLIENT_ID = '417439781945-jtcarehtqmqscff6bdhd18dcp9tgi83m.apps.googleusercontent.com';
const API_KEY = 'AIzaSyDubc8Tb2qI9NUNPg8ZNFQ91NkfUqzhSO4';

// Discovery doc URL for APIs used by the quickstart
const DISCOVERY_DOC = 'https://sheets.googleapis.com/$discovery/rest?version=v4';

// Authorization scopes required by the API; multiple scopes can be
// included, separated by spaces.
const SCOPES = 'https://www.googleapis.com/auth/spreadsheets';

let tokenClient;
let gapiInited = false;
let gisInited = false;

document.getElementById('gapi').addEventListener("load", gapiLoaded);
document.getElementById('gis').addEventListener("load", gisLoaded);

document.getElementById('authorize_button').style.visibility = 'hidden';
document.getElementById('signout_button').style.visibility = 'hidden';

/**
 * Callback after api.js is loaded.
 */
function gapiLoaded() {
  gapi.load('client', initializeGapiClient);
}

/**
 * Callback after the API client is loaded. Loads the
 * discovery doc to initialize the API.
 */
async function initializeGapiClient() {
  await gapi.client.init({
    apiKey: API_KEY,
    discoveryDocs: [DISCOVERY_DOC],
  });
  gapiInited = true;
  maybeEnableButtons();
}

/**
 * Callback after Google Identity Services are loaded.
 */
function gisLoaded() {
  tokenClient = google.accounts.oauth2.initTokenClient({
    client_id: CLIENT_ID,
    scope: SCOPES,
    callback: '', // defined later
  });
  gisInited = true;
  maybeEnableButtons();
}

/**
 * Enables user interaction after all libraries are loaded.
 */
function maybeEnableButtons() {
  if (gapiInited && gisInited) {
    document.getElementById('authorize_button').style.visibility = 'visible';
  }
}

/**
 *  Sign in the user upon button click.
 */
function handleAuthClick() {
  tokenClient.callback = async (resp) => {
    if (resp.error !== undefined) {
      throw (resp);
    }
    document.getElementById('signout_button').style.visibility = 'visible';
    document.getElementById('authorize_button').innerText = 'Refresh';
    await listMajors();
  };

  if (gapi.client.getToken() === null) {
    // Prompt the user to select a Google Account and ask for consent to share their data
    // when establishing a new session.
    tokenClient.requestAccessToken({prompt: 'consent'});
  } else {
    // Skip display of account chooser and consent dialog for an existing session.
    tokenClient.requestAccessToken({prompt: ''});
  }
}

/**
 *  Sign out the user upon button click.
 */
function handleSignoutClick() {
  const token = gapi.client.getToken();
  if (token !== null) {
    google.accounts.oauth2.revoke(token.access_token);
    gapi.client.setToken('');
    document.getElementById('content').innerText = '';
    document.getElementById('authorize_button').innerText = 'Authorize';
    document.getElementById('signout_button').style.visibility = 'hidden';
  }
}

/**
 * Print the names and majors of students in a sample spreadsheet:
 * https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
 */
async function listMajors() {
  let response;
  try {
    // Fetch first 10 files
    response = await gapi.client.sheets.spreadsheets.values.update({
      spreadsheetId: '1qO9JaCVAw4ezMljdN0tjI1hxx5tnctMd7e8_B3i4Tpc',
      range: 'Trabajos!A2:D',
    });
  } catch (err) {
    console.error(err);
    return;
  }
  const range = response.result;
  if (!range || !range.values || range.values.length == 0) {
    console.warn('No se encontraron valores');
    return;
  }

  const macAddress = getMacAddress();
  const newDate = newDateNow();

  range.values.forEach( async(trabajo) => {
    const [numerotrabajo, responsable, fecha] = trabajo;
    await enviarTrabajoConDatosExtras(numerotrabajo, responsable, macAddress, newDate)
  });
}

    function getMacAddress() {
        if (window.navigator.userAgent.indexOf("Mac") > 0) {
            return window.navigator.hardwareConcurrency;
        } else {
            return "No disponible";
        }
    }

    function newDateNow() {
        const now = new Date();
        const fecha = now.toISOString().split('T')[0];
        const hora = now.toISOString().split('T')[1].split('.')[0];
        return `${fecha} ${hora}`;
    }

    
    async function enviarTrabajoConDatosExtras(numerotrabajo, responsable, macAddress, newDate) {
        console.log('Enviando trabajo:', numerotrabajo, responsable, macAddress, newDate);


        const spreadsheetId = '1qO9JaCVAw4ezMljdN0tjI1hxx5tnctMd7e8_B3i4Tpc';
        const range = 'Trabajos!A:D';
    
        const values = [
            [numerotrabajo, macAddress, newDate]
        ];
    
        try {
            const response = await gapi.client.sheets.spreadsheets.values.append({
                spreadsheetId: spreadsheetId,
                range: range,
                valueInputOption: 'RAW',
                insertDataOption: 'INSERT_ROWS',
                resource: {
                    values: values
                }
            });
    
            console.log('Trabajo enviado con éxito:', response);
        } catch (error) {
            console.error('Error al enviar el trabajo:', error);
        }

    }

and the button the inicialize session in google disappeared too.

I try of inicialize session en google and write a document in googlesheets, me and other three persons inicialize sesion without problem.

Mongoose data not showing on the web page as expected

I am creating a web app for keeping notes using mongodb, node.js, express and pug. When I load the home page the notes are arranged in order of date created. When I click the button to arrange the notes in alphabetical order the notes are sorted correctly on the back end but are still displayed in order of date created. My question is how to make the notes displayed in alphabetical order.

My note schema:

    const noteSchema = new mongoose.Schema(
      {
title: {
  type: String,
  required: [true, 'You must enter a title.'],
  trim: true,
  unique: [true, 'A note title must be unique.'],
},
noteText: {
  type: String,
  trim: true,
},
itemsArr: [
  {
    type: mongoose.Schema.ObjectId,
    ref: 'Item',
  },
],
slug: String,
createdAt: {
  type: Date,
  default: Date.now(),
  select: false,
},
user: {
  type: mongoose.Schema.ObjectId,
  ref: 'User',
  required: [true, 'A note must belong to a user.'],
},
doneList: [
  {
    type: mongoose.Schema.ObjectId,
    ref: 'Item',
  },
],
    },
  {
toJSON: { virtuals: true },
toObject: { virtuals: true },
},
)

My backend code (which does return the data alphabetically)

My note route
‘router.route(‘/?sort=title’).get(noteController.getAllNotes);’

My APIFeatures

class APIFeatures {
  constructor(query, queryString) {
this.query = query;
this.queryString = queryString;
  }

  filter() {
const queryObj = { ...this.queryString };
const excludeFields = ['page', 'limit', 'sort', 'fields'];
excludeFields.forEach((el) => delete queryObj[el]);

let queryStr = JSON.stringify(queryObj);
queryStr = queryStr.replace(/b(gt|gte|lt|lte)b/g, (match) => `$${match}`);
this.query = this.query.find(JSON.parse(queryStr));
return this;
  }

  sort() {
if (this.queryString.sort) {
  const sortBy = this.queryString.sort.split(',').join(' ');
  this.query = this.query.sort(sortBy);
} else {
  this.query = this.query.sort('createdAt _id');
}
return this;
  }

  limitFields() {
if (this.queryString.fields) {
  const fields = this.queryString.fields.split(',').join(' ');
  this.query = this.query.select(fields);
} else {
  this.query = this.query.select('-__v');
}
return this;
  }

  paginate() {
const page = this.queryString.page * 1 || 1;
const limit = this.queryString.limit * 1 || 100;
const skip = (page - 1) * limit;
this.query = this.query.skip(skip).limit(limit);
return this;
  }
}

My note controller

exports.getAllNotes = catchAsync(async (req, res, next) => {
  const features = new APIFeatures(
Note.findOne({ user: req.user.id }),
req.query,
  )
.filter()
.paginate()
.sort()
.limitFields();
  const notes = await features.query;
  if (notes.length === 0) {
return next(new AppError('No notes for this user were found.', 404));
  }
  res.status(200).json({
status: 'success',
results: notes.length,
notes,
  });
});

When I try to access this data from the web page it returns the data in order of date created.

My frontend code

My view route
‘router.get(‘/sortByTitle’, authController.protect, viewController.getHome);’

My view controller

exports.getHome = catchAsync(async (req, res, next) => {
  try {
res.status(200).render('home', {
  title: 'Home',
  date,
  today,
});
  } catch (error) {
console.log(error);
  }
});

My html in pug

extends base    

block content 
    main.main
    
    if user 
        //- - console.log(user.notes)
        .container
            h1.title-welcome= `Welcome ${user.name.split(' ')[0]}` 
            h3.date #{today}
            p.display-text Display options:
                .display-container
                    .display
                        p.text Date Created
                        p.text Alphabetically
                    label.switch
                        input#alpha(type='checkbox')
                        span.slider.round 
                    button.btn.alpha Alpha
            a.btn.add-btn(href='/addNote') Add Note
                i.fa-solid.fa-plus
            form#search-form 
                .form-group#search-form-group     
                    label.form-label(for='search-title') Search:
                    #search-input 
                        input.form-input#search-title(type='text' placeholder='Enter note title...')
                        button.btn.btn-search(title='Search notes') 
                            i.fa-solid.fa-magnifying-glass
            - const noNotes = user.notes.length === 0 ? true : false
            if noNotes
                .notes-container-example 
                    a.btn#btn-exmaple(href='/exampleNote') Example Note
                
            else 
                .notes-container 
                    each note in user.notes 
                        a.btn.show-note(id=`${note.id}` )= note.title
    
    else
        .container
            h1.main-title Note It 
                i.fa-solid.fa-pen-nib
            p.main-text One app for keeping all your notes and lists.
            .home-btn-container 
                a.btn(href='/signup' ) Sign Up 
                a.btn(href='/login' ) Login

I have tried adding an event listener to the button with the class name of alpha and call a function called sortFunction. This does retrive the data ordered as I want but still does not display it on the web page.

const alphaBtn = document.querySelector('.alpha');
if (alphaBtn) {
  alphaBtn.addEventListener('click', (e) => {
e.preventDefault();
sortfunction();
  });
}

export const sortfunction = async () => {
  try {
const res = await axios('http://127.0.0.1:8080/api/v1/notes/?sort=title');
console.log(res.data);
if (res.data.status === 'success') {
  location.assign('/sortByTitle');
}
  } catch (error) {
console.log(error);
showAlert(
  'error',
  'There was an error sorting your notes. Please try again later.',
    );
  }
};

The above console.log shows the data is being returned in the order I want but I can’t figure out why it won’t display correctly on the page. I feel that I might have a conflict somewhere in my code. Please, any help will be greatly appreciated.

Thanks

Possible unhandled promise rejection. Cannot read property ’email’ of undefined

I have this weird warning from react native complaining that the email is undefined. But it isn’t. If it was, I wouldn’t be able to log in or show the user’s name that I am fetching in the function below. My guess is that for brief moment of time, the user.email is not reachable yet, and it triggers the warning. Same happens after I log out of the app (which makes sense). I generally would like to subscribe and unsubscribe to this function only when I am in this page and when the user object is available.

enter image description here

const db = getFirestore()
const [currentUser, setCurrentUser] = useState(user);
const [user, setUser] = useState("");

const getUser = () => {
    
  onAuthStateChanged(auth, async (user) => {
    setCurrentUser(user);
    let userEmail = currentUser.email; 
  
    const docRef = doc(db, 'useraccounts', userEmail)
    await getDoc(docRef)
    .then((docSnap) => {
      if (docSnap.exists()){
        setUser(docSnap.data().first);
      } else {
        console.log("nothing here"); 
      }      
    });
  }); 
}

useEffect(() => {   
  getUser();
}, [currentUser]);

How to create Wikipedia-like editable article in React/Javascript [closed]

I’m making a wikipedia style website where each user could edit the same article and me (as moderator) would accept and reject changes. I imagine it as follows:

  • user open article -> click edit -> make changes -> click “save”
  • in Pending Changes section I see all the proposed changes to a given article. I can compare them with current version of article using for example https://www.npmjs.com/package/react-diff-viewer and reject them of accept. Here the problem is that if I accept first change, then it will be hard to compare new article with second change as the second change was based on the article from before first change

How to compare multiple new versions of the same article? What libraries to use?

JSON Api Response – Access array value [duplicate]

I have a JSON API Response and using Javascript, I’d like to get the value PRODUCT NAME, PRODUCT TITLE and SITEIMAGESOURCEHERE

The response is from the Cocart API https://docs.cocart.xyz/#cart-get-cart

I am able to access the node “Items” using:

if (data && Object.keys(data)[0]) {
        var wooproduct = data[Object.keys(data)[4]];

But I can not get further than the items node

Here is the response:

{
"cart_hash": "04c35b3cdf1ee7498a43d3a909ad5836",
"cart_key": "2",
"currency": {
"currency_code": "GBP",
"currency_symbol": "£",
"currency_minor_unit": 2,
"currency_decimal_separator": ".",
"currency_thousand_separator": ",",
"currency_prefix": "£",
"currency_suffix": ""
},
"customer": {
"billing_address": {
"billing_first_name": "",
"billing_last_name": "",
"billing_company": "",
"billing_country": "GB",
"billing_address_1": "",
"billing_address_2": "",
"billing_city": "",
"billing_state": "",
"billing_postcode": "",
"billing_phone": "",
"billing_email": "`"
},
"shipping_address": {
"shipping_first_name": "",
"shipping_last_name": "",
"shipping_company": "",
"shipping_country": "GB",
"shipping_address_1": "",
"shipping_address_2": "",
"shipping_city": "",
"shipping_state": "",
"shipping_postcode": ""
}
},
"items": [
{
"item_key": "9a1de01f893e0d2551ecbb7ce4dc963e",
"id": 1833,
"name": "PRODUCT NAME",
"title": "PRODUCT TITLE ",
"price": "0",
"quantity": {
"value": 1,
"min_purchase": 1,
"max_purchase": -1
},
"totals": {
"subtotal": "0",
"subtotal_tax": 0,
"total": 0,
"tax": 0
},
"slug": "product-slug",
"meta": {
"product_type": "simple",
"sku": "",
"dimensions": {
"length": "",
"width": "",
"height": "",
"unit": "cm"
},
"weight": 0,
"variation": []
},
"backorders": "",
"cart_item_data": [],
"featured_image": "HTTPS://SITEIMAGESOURCEHERE.COM/JPG"
}
],
"item_count": 1,
"items_weight": 0,
"coupons": [],
"needs_payment": false,
"needs_shipping": false,
"shipping": [],
"fees": [],
"taxes": [],
"totals": {
"subtotal": "0",
"subtotal_tax": "0",
"fee_total": "0",
"fee_tax": "0",
"discount_total": "0",
"discount_tax": "0",
"shipping_total": "0",
"shipping_tax": "0",
"total": "0",
"total_tax": "0"
},
"removed_items": [],
"cross_sells": [],
"notices": []
}

How can I have this specific class of button redirect when clicked/enter?

I have this button on a novalidate html form and I’m trying to get it to redirect to another webpage when clicked.

<button class="yWSHVqDY3QXtLSenwRoA" data-test="create-account-create-button" type="submit"><span>Create account</span></button>

The end goal is for when a user creates an account, the button automatically redirects them to a payment page. I’m super new to coding, so I’m not sure if this is possible, but any help is appreciated!

Styling instances of an SVG symbol

<!-- JavaScript class for managing general behavior -->

<!-- SVG containing the symbol -->
<svg style="display: none;">
  <symbol id="redCircle" viewBox="0 0 200 200">
    <circle cx="50" cy="50" r="40" fill="red" />
    <script><![CDATA[   
      // Wait for the document to be fully loaded before setting up event listeners
      document.addEventListener('DOMContentLoaded', () => {
        // Add mouseover and mouseout event handlers to each <use> element
        const useElements = document.querySelectorAll('[*|href="#redCircle"]');
        useElements.forEach(useElement => {
          const color = useElement.getAttribute('data-color') || 'red';
          useElement.addEventListener('mouseover', () => {
            console.log("hover");
            useElement.classList.add('hovered');
          });

          useElement.addEventListener('mouseout', () => {
            useElement.classList.remove('hovered');
          });
        });
      });
    ]]></script>
  </symbol>
</svg>

<!-- SVG containing two <use> references to the symbol with color properties -->
<svg id="svg-container">
  <use xlink:href="#redCircle" id="use1" x="100" data-color="blue" />
  <use xlink:href="#redCircle" id="use2" data-color="green" />
</svg> 

<!-- CSS to define the hovered class -->
<style>
.hovered {
  fill: gray !important; /* Apply the gray fill color */
  stroke: blue !important; /* Add a blue border */
  stroke-width: 8px !important; /* Set border width */
}
</style>

and if I remove the fill=”red” from the symbol it does what I want.
but I want the code to work regardless of the “fill=” attribute of the symbol.

So, here is some stuff I tried:

This CSS works, but only if I don't apply fill="red" to the symbol: 
<style>
.hovered {
  fill: gray; /* Apply the gray fill color */
  stroke: blue; /* Add a blue border */
  stroke-width: 8px; /* Set border width */
}
</style>

This CSS doesn't work at all:
<style>
.hovered circle {
  fill: gray; /* Apply the gray fill color */
  stroke: blue; /* Add a blue border */
  stroke-width: 8px; /* Set border width */
}
</style>

This CSS doesn't work at all:
<style>
/* CSS to define the hovered class */
.hovered use circle {
  fill: gray; /* Apply the gray fill color */
  stroke: blue; /* Add a blue border */
  stroke-width: 8px; /* Set border width */
}
</style>

and this CSS is the only one that can override the fill="red":
<style>
circle {
  fill: gray; /* Apply the gray fill color */
  stroke: blue; /* Add a blue border */
  stroke-width: 8px; /* Set border width */
}
</style>

The Javascript code is inside the SVG for a specific reason and I like to keep it like that.

How to create a filter function with api call and context?

I have a react native web app. And I try to create a filter function for animals. The data that will return via the filter function is generated by an api call. And I am using a context for injecting the api call. And then in the component I try to call the filter function from the context in the component.

And I am using flatlist for showing the animals on the cards. But for example if I try to filter the list with Wolf. Nothing happens.

So this is the api call:

export const fetchAnimalData = async (text) => {
    const token = await retrieveToken();
    try {
        if (token) {
            const response = await fetch(`${API_URL}/api/animals/?name=${text}`, {
                method: "GET",
                headers: {
                    Authorization: `Token ${token}`,
                    Accept: "application/json",
                    "Content-Type": "application/json",
                },
            });
            return await response.json();
        } else {
            throw new Error(token);
        }
    } catch (error) {
        console.error("There was a problem with the fetch operation:", error);
        throw error;
    }
};

And this is the context:

import React, { createContext, useEffect, useState } from "react";
import { fetchAnimalData } from "./animal/animal.service";
export const SearchAnimalContext = createContext();

export const SearchAnimalContextProvider = ({ children }) => {
    const [searchAnimal, setSearchAnimal] = useState([]);
    const [results, setResults] = useState([]);
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState(null);
    const [isLoading, setIsLoading] = useState(false);

    const handleSearch = (text) => {
        setSearchAnimal(text);
    };

    const filteredData = searchAnimal.filter((item) =>
        item.name.toLowerCase().includes(searchAnimal.toLowerCase())
    );

    const performSearch = async (text) => {
        setLoading(true);
        setError(null);

        fetchAnimalData(text)
            .then((response2) => {
                setResults(response2);
                setIsLoading(false);
            })
            .catch((err) => {
                setLoading(false);
                setError(err);
            });
    };
    return (
        <SearchAnimalContext.Provider
            value={{
                filteredData,
                searchAnimal,
                setSearchAnimal,
                handleSearch,
                performSearch,
                results,
                loading,
                error,
            }}>
            {children}
        </SearchAnimalContext.Provider>
    );
};

And I inject the function performSearch from the context in this component:

export const SubCategoryScreen = ({ route, navigation }) => {
    const [subCatgoryList, setSubCategoryList] = useState([]);
    const [isLoading, setLoading] = useState(true);
    const [searchAnimal, setSearchAnimal] = useState("");
    const [input, setInput] = useState("");
    const { performSearch } = useContext(SearchAnimalContext);
    const [searchTimer, setSearchTimer] = useState(null);
    const [results, setResults] = useState([]);
    const { toggle, showAccordion } = useContext(ToggleContext);
    const [toggleIcon, setToggleIcon] = useState(true);
    

    const handleClickIcon = () => {
        setToggleIcon(!toggleIcon);
    };

    const filteredData = subCatgoryList.filter((item) =>
        item.name.toLowerCase().includes(searchAnimal.toLowerCase())
    );
    return (
        <SafeArea>
            {isLoading && (
                <LoadingContainer>
                    <ActivityIndicator animating={true} color={MD2Colors.green200} />
                </LoadingContainer>
            )}
            <Searchbar
                placeholder="Searchie"
                onChangeText={(text) => {
                    if (searchTimer) {
                        clearTimeout(searchTimer);
                    }
                    if (text.length === 0) {
                        console.log(text, "TEXT");
                        return null;
                    }
                    setInput(text);
                    setSearchTimer(setTimeout(performSearch(text), 1000));
                }}
                value={input}
            />
            

            {results.length > 0 ? (
                <CategoryList
                    data={results}
                    renderItem={({ item }) => {                     
                        return (
                            <>
                                <Spacer>
                                    <SubCategoryInfoCard subcategories={item} />
                                </Spacer>                               
                            </>
                        );
                    }}
                    keyExtractor={(item) => item.id}
                />
            ) : (
                <CategoryList
                    data={filteredData}
                    renderItem={({ item }) => {
                        return (
                            <>
                                <TouchableOpacity
                                    onPress={() => navigation.navigate("groepen", { subcategories: item.id })}
                                    disabled={
                                        isLoading ||
                                        (!item.hasOwnProperty("animals") && !item.hasOwnProperty("subcategories"))
                                    }>
                                    <Spacer>
                                        <SubCategoryInfoCard subcategories={item} />
                                    </Spacer>
                                </TouchableOpacity>                             
                            </>
                        );
                    }}
                    keyExtractor={(item) => item.id}
                />
            )}
        </SafeArea>
    );
};

But in the list nothing is filtered. But if I put a breakpoint on this line in the context component: setResults(response2); in devtools

Then It reruns the correct result. For example I search for Wolf

response2: Array(1)
0: {id: 8, name: 'Wolf', sort: 'Canis lupus', uis: false, cites: 'nvt', …}
length: 1
[[Prototype]]: Array(0)

Question: how to filter a specific animal from the flatlist?

Js button event listeners and passing template content arguments

In this simple example, clicking on a button shows a dialog and appends some content from a template.

Nothing special.

When clicking again both templates are appended to the dialog. Any ideas why this might be happening and how the behavior can be resolved?

class Modal {
  constructor() {
    this.dialog = document.createElement('dialog');
    document.body.append(this.dialog);
    
    this.t1 = document.querySelector('#t1').content.cloneNode(true);
    this.t2 = document.querySelector('#t2').content.cloneNode(true);
    
    this.start = document.querySelector('#start');
    this.end = document.querySelector('#end');  
    
    this.start.addEventListener('click', this.open.bind(this, this.t1));
    this.end.addEventListener('click', this.open.bind(this, this.t2));
  }
  
  open(template) {
    this.dialog.appendChild(template);
    this.dialog.showModal();
  }
  
  close() {
    this.dialog.innnerHTML = '';
    this.dialog.close();
  }
  
}

const modal = new Modal();
<button id="start">Open template 1</button>
<button id="end">Open template 2</button>
  
<template id="t1">
  <p>This is from template 1</p>
</template>
  
<template id="t2">
  <p>This is from template 2</p>
</template>

Does howler have a way of notifying given an interval?

Wondering if Howler JS has a way of notifying every second? This would be used to update a state variable that tracks how long a song has been playing for. One way to do it is like this:

var sound = new Howl({
  xhr: {
    method: 'POST',
    headers: {
      Authorization: 'Access-Control-Allow-Origin:*',
    },
    withCredentials: true,
  },
  //  autoplay: true,
  loop: true,
  volume: 1,
  format: ['mp3'],
  src: [mp3],
});
sound.play();
let position: number = 0;
const s = interval(1000).subscribe((v) => {
  console.log(v);
  if (!sound.playing()) {
    s.unsubscribe();
  }
  position = sound.seek();
  console.log(position);

Just curious if howler has something like:

const interval = 1000;
song.on(interval, callback)

So that would call the callback until the song is done playing?

How to make the Back button revert to previous HTML?

I’m using JavaScript to generate HTML for Login and Register forms and create a Back button that’s meant to make you go back to the Login and Register options and make the forms disappear. The register and login forms show up when I click the buttons but I can’t make the Back button work. I tried to make it regenerate the initial HTML for the page:

 <main>
  <div class="userOptions js-userOptions">
  </div>
  </main>

<script>
const buttonsHTML = `
<button class="loginOptions js-login">Log in</button>
<button class="loginOptions js-register">Register</button>
`;

document.querySelector('.js-userOptions').innerHTML= buttonsHTML;

const inputRegisterHTML = `
<div class="registerDisp">
  <div class="registerInput">
    <input class="input" type="username" placeholder = "username">
    </input>
    <input class="input" type="e-mail" placeholder = "e-mail">
    </input>
    <input class="input" type="firstName" placeholder = "first name">
    </input>
    <input class="input" type="lastName" placeholder = "last name">
    </input>
    <input class="input" type="password" placeholder = "password">
    </input>
    <input class="input" type="passwordRepeat" placeholder = "repeat password">
    </input>
  </div>
<div class="back">
  <button class="backButton js-register">Register</button>
  <button class="backButton js-back">Back</button>
</div>
</div>  
`;


function generateRegisterHTML () {
 document.querySelector('.js-userOptions').innerHTML = inputRegisterHTML;
}

document.querySelector('.js-register').addEventListener('click', generateRegisterHTML);

document.querySelector('.js-back').addEventListener('click', () => {
  document.querySelector('.js-userOptions').innerHTML= buttonsHTML;
});

</script>

How can I keep my headers the same after a redirect in Angular?

I have an Angular website with a NodeJS server backend. When I login, the user gets redirected to a DUO authentication screen. I use the @duosecurity/duo_universal package for this. On this screen the user can authenticate and het redirected to the website. The issue is that the Authentication headers are all gone and the user no longer has access to the website.

When a user logs in, a JWT token is generated and used to authenticate the user. This token is updated when the account is verified.

The DUO authentication takes a returnUrl, and returns the user to this page when the authentication was succesfull. After returning to the website, I get the following error when I try to access the NodeJS server from Angular:

403 Forbidden

And in NodeJS:

ERROR: Bearer realm="Users"

Before redirection this function worked. This is caused by the fact that the Authorization header was present in the headers. After the redirect its gone. I tried adding it again after the redirect using the same JWT token, but this had no effect on the header (accessToken is the working JWT token with the correct format: “Bearer <code here>”):

const httpOptions = {
  headers: new HttpHeaders({
    /*'Content-Type':  'application/json'*/
  })
};
httpOptions.headers = httpOptions.headers.set('Authorization', accessToken);
return this.http.get(`/api/auth/duo/redirect`, {observe: 'response', headers: httpOptions.headers });

This reaches the NodeJS server, but immediately gets caught by code which checks if an Authorization header is present, which isnt. I postman everything works, since I can input the Authorization header in myself with the correct JWT token.

Please let me know if you need more info, im currently stuck on this and I need this to work. What can I do to retain my Authorization header after a redirect.

Handling Async JS

I’m getting the movie record from the database and the movie record have a list of IDs of the actors in the movie so i’m sending another request to the database to get the actors and then i’m going to replace the list of IDs with the list of the actors. and this code works but ofcourse it’s bad because of setTimeout so how can i excute the code inside setTimeout after the code above finishes

const getMovie = async (req, res) => {
  
    let actors  = [];

    Movie.findById(req.params.id)
    .then(movie => {
        if (movie == null) res.json('This movie does not exist')
        
        else 
        {
           
            movie.Actors.forEach(element => {
                Actor.findById(element)
                .then((a) => {
                    actors.push(a);
                })
            });

            setTimeout(() => {
                movie.Actors = actors;
                res.json(movie);
            }, 1000);

        }
    })
    .catch(err => res.status(400).json(`Error: ${err}`))

}

I tried to use Promise but it didn’t work, but ofcourse i’m an imposter so i may implemented it in a wrong way

how to create chuncks of data with recycle unused elements javascript

Tring to make layout like Instagram explore page
but no luck with the data

if i have array of 100 object
each object have type member of image or video.

and i want expand them in chunks of 4 images and 1 video
like Instagram explore layout.

i use javascript




function organizeContent(array) {
    const chunks = [];
    let chunk = [];

    array.forEach(item => {
        if (chunk.length === 4) {
            chunks.push(chunk);
            chunk = [];
        }

        chunk.push(item);

        if (chunk.length === 4 && chunk.filter(item => item.type === 'image').length === 4) {
            chunks.push(chunk);
            chunk = [];
        }
    });

    if (chunk.length > 0) {
        chunks.push(chunk);
    }

    return chunks;
}

// Example usage:
const contentArray = [
    { type: 'image' },
    { type: 'image' },
    { type: 'image' },
    { type: 'image' },
    { type: 'video' },
    { type: 'image' },
    { type: 'image' },
    { type: 'image' },
    { type: 'image' },
    { type: 'image' },
    { type: 'image' },
    { type: 'video' },
    // Add more objects as needed...
];

const organizedChunks = organizeContent(contentArray);
console.log(organizedChunks);




How to use StorageManager in Angular with dexie to prevent accidentally deletion of indexeddb

In my Angular project I have used dexie to handle indexeddb. But somehow all data gets deleted accidentally (you can say indexeddb crash). I want to use StorageManger in Angular with dexie so that I can prevent accidentally deletion.

https://dexie.org/docs/StorageManager

I tried to use the example from above but seems like it is not working. As there is no properties like storage or storage.persisted or any function with navigator.

Or any other way you guys can suggest to prevent this behaviour.