Vue JS add a class when an item is clicked and remove it when a sibling item is clicked

In a navigation list. I am having a class added on click, and it goes a way when I click again. It is adding the class to all the items of the list. I just wish to make one item active at a time on Click. Also, I have a click with two actions ( Scroll and then add a class)

<b-navbar class="d-flex flex-column align-items-start>
                    <b-navbar-brand tag="h3" class="m-0">List Index</b-navbar-brand>
                    <b-navbar-nav v-for="(linkItem, index) in linkItems" :key="index">
                        <b-nav-item :class="{ active: isActive }" class="pl-2" @click="scrollTo(`${linkItem.id}`), (isActive = !isActive)">
                            {{ linkItem.title }}
                        </b-nav-item>
                    </b-navbar-nav>
                </b-navbar>

And the methods are

data() {
        return {
            isActive: false,
            linkContent: [] as any
        };
    },

scrollTo { This is working fine},

activeLink() {
            this.isActive = true;
        }

    }
});

I need help making the class only apply to the active element.

Thanks

Typescript dynamic class functions from generics

I want to do something like

class C<R extends Record<string, unknown>> {
  [K extends keyof R](param: R[K]) {
    console.log(K, param); // have access to both key and value
  }
}

Is there a way to achieve this with typescript?

I read this post, but it only generates the names and not the implementations of the functions.

React Native – navigation on top right header button

A screen of my app (FeedScreen) has a top-right header button. I want that button to navigate to another screen on press.

This is my code:

const Stack = createNativeStackNavigator();

function App({ navigation }) {
return (
  <>
  <StatusBar hidden />
  <NavigationContainer>
    <Stack.Navigator initialRouteName="Home">
      <Stack.Screen name="Home" component={HomeScreen} />
      <Stack.Screen name="Login" component={LoginScreen} />
      <Stack.Screen name="Signup" component={SignupScreen} />
      <Stack.Screen name="TestScreen" component={TestScreen} />
      <Stack.Screen name="CarouselScreen" component={CarouselScreen} />
      <Stack.Screen name="SettingsScreen" component={SettingsScreen} />
      <Stack.Screen name="InsertNumberScreen" component={InsertNumberScreen} />
      <Stack.Screen name="FeedScreen"
       component={FeedScreen}
       options={{
        title: 'My screen',
        headerStyle: {
          backgroundColor: '#262423',
        },
        headerTintColor: '#fff',
        headerTitleStyle: {
          fontWeight: 'bold',
        },
        headerRight: () => (
          <Button
            onPress={() => navigation.navigate('UploadPictureScreen')}
            title="+"
            color="#fff"
          />
        ),
      }} 
      />
      <Stack.Screen name="UploadPictureScreen" 
        component={UploadPictureScreen} 
        options={{
          title: 'Upload a picture',
          headerStyle: {
            backgroundColor: '#262423',
          },
          headerTintColor: '#fff',
          headerTitleStyle: {
            fontWeight: 'bold',
          },
        }}
      />
    </Stack.Navigator>
  </NavigationContainer>
  </>
);
}

Unfortunately, it returns “Undefined is not an object (evaluating ‘navigation.navigate’)”.

How can I copy text from div on ios?

html

<div id="id">some text</div>

js

function copyText(id) {
  var input = document.getElementById(id);
  var range = document.createRange();
  range.selectNode(input);
  window.getSelection().removeAllRanges();
  window.getSelection().addRange(range);
  document.execCommand("copy");
  window.getSelection().removeAllRanges();
};

I’ve found solution for copying text from div, but seems like it doesn’t work on ios(safari). Is it possible to change it for making it work for ios ? For checking is some function I use will work on ios , I was using https://caniuse.com/ and seems , like nothing restricted there from what I use .

Split JS string based on multiple different RegExr conditions

I have a JS string, say:

var testString = "words here, svg_icon('Var-1') svg_icon('Var_2'), and even more words here";

I understand how to match the string based on a fixed value e.g. if I want to match on svg_icon:

var testString = "words here, svg_icon('Var-1','var_3') svg_icon('Var_2'), and even more words here";
var filterMatch = /(svg_icon)/;
var results = testString.match(filterMatch);

results.forEach((result) => {
  console.log(result);
})

This logs the 2 matches it finds, which I’m expecting:

"svg_icon"
"svg_icon"

What I’m trying to do is match the expression so my output will be:

"svg_icon('Var-1','var_3')"
"svg_icon('Var_2')"

I think this is possible with Regular expressions, but cannot find how to deal with combining conditions whilst matching the changing “variable” names (e.g.'Var-1','var_3' and Var_2) that may contain special characters (just dashes and underscores).

Any help on what RegEx I can use in this situation, or if this is in fact possible with so many conditions.

Thanks in advance for any advice!

Happo.io Integration with playwright, mobile is a bit different than desktop how do I configure

I have two different environments to run happo tests with playwright using the happo playwright integration. The mobile environment is different from the desktop and so I need to have 2 test files one for mobile and one for desktop. The problem is defining the happo.js and playwright.config.js so that i use the correct browser and configurations based on mobile or desktop. Is this possible?

My game Show some extra space in below on Mobile Device

I am developed one Game using HTML ,CSS & JavaScript and it is responsive on Desktop but if I will try to make it responsive on Mobile then it show some extra Blue Color Space at bottom . Can anyone help to tackle this problem?

Website is live onhttps://yashjee003.github.io/guessnumber.github.io/

error

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  background-color: #001e6c;
  text-align: center;
  width: auto;
}

main {
  background-color: aliceblue;
  width: 40%;
  padding: 2rem 2rem;
  margin: 2rem auto;
  border: solid black;
  border-width: 5px;
}
.welcome-screen {
  height: auto;
}
img {
  width: 90%;
  max-width: 50%;
  margin: 3rem auto;
}

h2 {
  font-family: "Montserrat", sans-serif;
  margin-top: 2.5rem;
}
h3 {
  font-size: 1rem;
}
.event-buttons {
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: center;
  margin: 2rem 1rem;
}
button {
  margin: 0.5rem auto;
  padding: 1.8rem;
  color: white;
  background-image: linear-gradient(#001e6c, #035397);
  border-radius: 1rem;
  border: none;
  cursor: pointer;
  font-size: 1.15rem;
  font-family: Sans;
  width: 59%;
}
button:hover {
  box-shadow: 0 1px 0 1px #032322;
}
#button-child {
  background: linear-gradient(#673fd7, #673fd7);
}

/* // User Play area  */

.user-guess {
  font-size: 20px;
  margin-bottom: 2rem;
}

.user-guess input {
  padding: 2rem 4rem;
  border-style: none;
  background-color: transparent;
  margin-top: 2rem;
  font-size: 15px;
}

#guess-result {
  margin: 30px;
  text-align: left;
  margin: 1.2rem auto;
}

#guess-result .attempts {
  font-size: 1.1rem;
  color: red;
}

.info {
  display: flex;
  justify-content: space-between;
  font-family: Montserrat;
  margin-bottom: 2rem;
}

#event-screen {
  height: auto;
  /* margin-top: 50px; */
}

/* // Responsive */

@media (max-width: 480px) {
  body {
    /* width: 10; */
  }
  h2 {
    font-size: 21px;
    margin-top: 1rem;
  }

  main {
    width: 100%;
    border-width: 5px;
    margin: 0;
    height: fit-content;
    height: max-content;
    height: auto;
  }
  img {
    max-width: 67%;
  }
  button {
    width: 82%;
    margin: 0.5rem auto;
    padding: 1rem;
    border-radius: 0.5rem;
    font-size: 1rem;
  }
  .user-guess input {
    padding: 1.2rem 1rem;
    text-align: center;
  }

  h3 {
    font-size: 0.9rem;
    font-style: normal;
    font-weight: 600;
  }
  .info {
    flex-direction: column;
  }

  #guess-result .attempts {
    margin-top: 9px;
  }
}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="style.css" />
    <link rel="preconnect" href="https://fonts.googleapis.com" />
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
    <link
      href="https://fonts.googleapis.com/css2?family=Josefin+Sans:wght@300;400&family=Montserrat:ital,wght@0,500;1,500&display=swap"
      rel="stylesheet"
    />
  </head>
  <body onload="randomNumber()">
    <main>
      <!-- Welcome Screen -->
      <section id="welcome-screen">
        <div id="title-image">
          <h2>Guess The Random Number Between 1-100</h2>
          <img src="/images/game.svg" alt="logo" />
        </div>

        <div id="event_guess">
          <h2>Select The Difficulty</h2>
          <div class="event-buttons">
            <button onclick="easyMode()">Easy: 10 Attempts</button>
            <button onclick="hardMode()" id="button-child">
              Hard: 5 Attempts
            </button>
          </div>
        </div>
      </section>

      <!-- Event Screen -->

      <section id="event-screen">
        <div id="even-button">
          <button onclick="startNewGame()" id="event-button">New Game</button>
        </div>
        <div class="user-guess">
          <h2>Your Guess</h2>
          <input
            type="number"
            name="Guess"
            id="guess-number"
            placeholder="Enter your Guess"
            onchange="userData()"
            ;
          />
        </div>

        <div id="guess-result">
          <div class="info">
            <h3>Number of previous attempts</h3>
            <span class="attempts">0</span>
          </div>

          <div class="info">
            <h3>Number of previous guesses</h3>
            <span class="attempts" id="previous">0</span>
          </div>
        </div>
      </section>
    </main>
    <script src="/index.js"></script>
  </body>
</html>

Problem Transpiling HTML to JSX of HTML code generated by showdown

I’m using showdown to create some objects using the Markdown editor and in particular I want to include React javascript code in the markdown using the backtick ` ` characters, but my code is not working.

If I look at the markdown preview it’s working fine, but when I try to convert it to JSX it breaks.

I can’t figure out if it is an escaping error or something else. It seems it’s trying to parse the code but it shoudn’t, since it’s inside a <code> </code> tag in the generated HTML.

Here is my code:

import { observer } from "mobx-react-lite"
import React, {useMemo} from "react"
import Showdown from 'showdown'
import { useStore } from "../store/Provider"
const buble = require('buble');

const MarkdownToJSX = ({ md }) => {
    // if (typeof md !== 'string') return null;
    const makeComponent = useMemo(() => {
      const converter = new Showdown.Converter({
        tables: true,
        simplifiedAutoLink: true,
        strikethrough: true,
        tasklists: true,
      });
      // wrap converted HTML in closures
      //   const html = <>${converter.makeHtml(md)}</>
      const html = converter.makeHtml(md)
      const htmlWrapped = '<>'.concat(html).concat('</>')
      const code = buble.transform(htmlWrapped).code;
      // eslint-disable-next-line
      const makeComponent = Function('React', 'return ' + code)
      console.log(makeComponent)
      return makeComponent;
    }, [md]);
  
    return makeComponent(React);
  };

function Bounties() {
    const store = useStore()

    return (
        store.bounties.map( bounty => (
            <div className="bounties" key={bounty.id}>
                <h2>{bounty.title}</h2> 
                <div >
                    <MarkdownToJSX md={bounty.body}/>
                </div>
            </div>
        ))
    )
}

export default observer(Bounties)

Here is an example of the problems I’m facing: https://stackblitz.com/edit/react-8fcgyb

React cannot access multidimensional array state value

In my react application I am setting the state value as an array using the below code.

const [ds_data, setDsData] = useState([]);
    let ds_arr = res.data.map((elem, index) => {
                  return elem.split(" ")
                })
                setDsData(ds_arr)

The values in the array when I use console.log() are

enter image description here

The problem is when I try to display the value of the multidimensional array using {ds_data[0][0]}, I am getting the error Uncaught TypeError: Cannot read properties of undefined (reading '0') in the console. When I used {ds_data[0]} it is showing all the array values as a single string 363861319e9d5720089762a51d24a86dd1402dbba64771c9

Ambigous data type in javascript

enter image description here

I print a variable by console.log(TotalTime) and this is the result. It looks like an array but it’s not. There are some other console.log commands:
console.log(typeof TotalTime) => Object
console.log(TotalTime[0]) => undefine
i need to access the element shown in the picture but i couldn’t.
How can I get it? I need to calculate the sum of it.

Why NestJS validation pipe fail in unit test when field is missing but skipMissingProperties is true?

I have a custom validation pipe in NestJS where I set skipMissingProperties to true, so when I don’t send a field that is decorated with IsDefined the validation will not throw exception. For example, if the DTO is:

class ModelDTO {
  @IsDefined()
  @IsNumber()
  requiredNumber1: number;

  @IsDefined()
  @IsNumber()
  requiredNumber2: number;
}

and the actual object the validation pipe accepts is:

{
  requiredNumber2: 1
}

it doesn’t fail (I save some log in this case).

When I do e2e tests it works fine – I can see the validation pipe continues to the controller and that I get the desired log.

For some reason when I do unit-tests for some reason the same case failes with Bad Request (400) exception, the error message is requiredNumber2 should not be null or undefined.

Why the unit-test fails while the e2e works well? (By the way – in manual tests the pipe also works well).

React shwoing a blank screen without any error mesagges (contextapi used)

I’m building a react Amazon clone, so in order to give the user the ability to add a product into his basket (as the first version of all the future checkout system), I’ve used ContextApi to manage this.

when I finished writing ContextApi code and adding it to the index.js file so I could access the data I got a blank screen with absolutely no error messages. and I don’t know where is exactly the problem. so help me in here please <3

this is the StateProvider.js file :

import React , { createContext, useContext, useReducer} from 'react'


export const StateContext = createContext();


export const StateProvider = ({reducer , initialValue, children}) => {
    <StateContext.Provider value={useReducer(reducer, initialValue)}>
        {children}
    </StateContext.Provider>
};


export const useStateValue = () => useContext(StateContext)

and this is the reducer.js file :

export const initialState = {
    basket: [], 
};


const reducer = (state, action) => {
    switch(action.type) {
        case "ADD_TO_BASKET":
            return{
                ...state,
                basket: [...state.basket, ...action.item]
            };
            default: 
            return state;
    };
};

export default reducer;

and this is the index.js file :

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { StateProvider } from './Special_components/StateProvider';
import reducer, { initialState } from './Special_components/reducer';


const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
    <React.StrictMode>
        <StateProvider>
            <App reducer={reducer} initialState={initialState} />
        </StateProvider>
    </React.StrictMode>

)

Menu doesn’t close after clicking link in nav

I have problem with this code.
When i open menu in smaller resolution(mobile resolution) and click on some link from the menu its not closing, its still there the menu. Can you help me? I think there is missing something in js code but i dont know what i can write more to close menu after clicking on the link from the menu.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Sticky Navigation Bar | CodingNepal</title>
    <link rel="stylesheet" href="style.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"/>
</head>
<body>
  <nav class="navbar">
    <div class="content">
      <div class="logo">
        <a href="#">CodingNepal</a>
      </div>
      <ul class="menu-list">
        <div class="icon cancel-btn">
          <i class="fas fa-times"></i>
        </div>
        <li><a href="#">Home</a></li>
        <li><a href="#">About</a></li>
        <li><a href="#">Services</a></li>
        <li><a href="#">Features</a></li>
        <li><a href="#">Contact</a></li>
      </ul>
      <div class="icon menu-btn">
        <i class="fas fa-bars"></i>
      </div>
    </div>
  </nav>
  <div class="banner"></div>
  <div class="about">
    <div class="content">
      <div class="title">Responsive Sticky Navigation Menu Bar on Scroll using HTML CSS & JavaScript</div>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quo impedit atque consequatur! Iusto distinctio temporibus repellendus labore odit adipisci harum ipsa beatae natus, eum eius, hic aperiam odio! Quasi molestias magnam illo voluptatem iusto ipsam blanditiis, tempore cumque reiciendis quaerat vero tenetur, sequi dolores libero voluptas vitae voluptate placeat dolorum modi ipsa nisi repellat facilis aliquam asperiores. Aut nam repellat harum quas saepe dolorum voluptates ratione, itaque consectetur explicabo a facilis rem mollitia maxime repudiandae fuga reprehenderit, odio cum incidunt labore molestiae quis non perferendis ipsam. Illum, in, deserunt. Ipsa.</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Impedit hic excepturi nobis id, eos dolor libero, nam assumenda, at culpa quos perspiciatis ratione ea modi! Natus sapiente a, explicabo sit quisquam eligendi esse provident eos enim doloremque blanditiis aut placeat veniam, libero nostrum quae. Ipsam, iste reprehenderit minima accusantium illo dolorem recusandae, ipsa autem quidem reiciendis a mollitia sit tenetur.</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sint doloremque perspiciatis voluptate ducimus reiciendis rem expedita voluptatibus dicta harum, quo, aspernatur maiores possimus officia quod? Aliquid molestiae illo sequi, tempora perferendis at incidunt nam porro voluptatibus, iste aperiam blanditiis adipisci ducimus repellendus distinctio nostrum ipsum! Voluptas facilis cum, atque tempora magnam beatae sequi! Doloribus expedita, cupiditate quo quod nemo aliquam, mollitia cum ea nam ullam soluta temporibus! Repudiandae incidunt consequatur distinctio deleniti obcaecati sit facilis unde, quisquam veniam ad doloribus!</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet veniam error deleniti cum beatae non assumenda illum est dolores, possimus suscipit quibusdam eveniet id fuga dolore unde modi, sapiente voluptas. Mollitia veritatis explicabo cumque enim quia voluptates provident totam perferendis excepturi animi assumenda optio minus laudantium eveniet possimus amet blanditiis dolore in fuga atque, earum officia tempora quam similique est.</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Itaque ad sunt distinctio quidem incidunt cupiditate sequi deleniti, corrupti officia nam veritatis facilis veniam dolorum enim nisi ipsum dolor rem! Doloribus, eaque odit voluptatem iste laboriosam provident facere quo. Cum repellat pariatur, error ratione repellendus nisi quam culpa tempora facere in atque nesciunt, magni est aliquid unde soluta optio! Dolore pariatur, quaerat quo in cupiditate deleniti exercitationem. Facilis suscipit corporis unde aut minima nihil, eum molestias itaque, tenetur, beatae ipsa at!</p>
    </div>
  </div>
  <script>
    const body = document.querySelector("body");
    const navbar = document.querySelector(".navbar");
    const menuBtn = document.querySelector(".menu-btn");
    const cancelBtn = document.querySelector(".cancel-btn");
    menuBtn.onclick = ()=>{
      navbar.classList.add("show");
      menuBtn.classList.add("hide");
      body.classList.add("disabled");
    }
    cancelBtn.onclick = ()=>{
      body.classList.remove("disabled");
      navbar.classList.remove("show");
      menuBtn.classList.remove("hide");
    }
    window.onscroll = ()=>{
      this.scrollY > 20 ? navbar.classList.add("sticky") : navbar.classList.remove("sticky");
    }
  </script>
</body>
</html>
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;300;400;500;600;700&display=swap');
*{
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: 'Poppins', sans-serif;
}
/* custom scroll bar */
::-webkit-scrollbar {
    width: 10px;
}
::-webkit-scrollbar-track {
    background: #f1f1f1;
}
::-webkit-scrollbar-thumb {
    background: #888;
}
::selection{
  background: rgb(0,123,255,0.3);
}
.content{
  max-width: 1250px;
  margin: auto;
  padding: 0 30px;
}
.navbar{
  position: fixed;
  width: 100%;
  z-index: 2;
  padding: 25px 0;
  transition: all 0.3s ease;
}
.navbar.sticky{
  background: #1b1b1b;
  padding: 10px 0;
  box-shadow: 0px 3px 5px 0px rgba(0,0,0,0.1);
}
.navbar .content{
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.navbar .logo a{
  color: #fff;
  font-size: 30px;
  font-weight: 600;
  text-decoration: none;
}
.navbar .menu-list{
  display: inline-flex;
}
.menu-list li{
  list-style: none;
}
.menu-list li a{
  color: #fff;
  font-size: 18px;
  font-weight: 500;
  margin-left: 25px;
  text-decoration: none;
  transition: all 0.3s ease;
}
.menu-list li a:hover{
  color: #007bff;
}
.banner{
  background: url("banner.jpg") no-repeat;
  height: 100vh;
  background-size: cover;
  background-position: center;
  background-attachment: fixed;
}
.about{
  padding: 30px 0;
}
.about .title{
  font-size: 38px;
  font-weight: 700;
}
.about p{
  padding-top: 20px;
  text-align: justify;
}
.icon{
  color: #fff;
  font-size: 20px;
  cursor: pointer;
  display: none;
}
.menu-list .cancel-btn{
  position: absolute;
  right: 30px;
  top: 20px;
}
@media (max-width: 1230px) {
  .content{
    padding: 0 60px;
  }
}
@media (max-width: 1100px) {
  .content{
    padding: 0 40px;
  }
}
@media (max-width: 900px) {
  .content{
    padding: 0 30px;
  }
}
@media (max-width: 868px) {
  body.disabled{
    overflow: hidden;
  }
  .icon{
    display: block;
  }
  .icon.hide{
    display: none;
  }
  .navbar .menu-list{
    position: fixed;
    height: 100vh;
    width: 100%;
    max-width: 400px;
    left: -100%;
    top: 0px;
    display: block;
    padding: 40px 0;
    text-align: center;
    background: #222;
    transition: all 0.3s ease;
  }
  .navbar.show .menu-list{
    left: 0%;
  }
  .navbar .menu-list li{
    margin-top: 45px;
  }
  .navbar .menu-list li a{
    font-size: 23px;
    margin-left: -100%;
    transition: 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55);
  }
  .navbar.show .menu-list li a{
    margin-left: 0px;
  }
}
@media (max-width: 380px) {
  .navbar .logo a{
    font-size: 27px;
  }
}

Wait for a fetch/then chain at a specific step of another fetch/then chain

I have two fetch requests.

The first one build a select element:

fetch("data/select.json")
  .then(response => response.json())
  .then(data => {
    // populate select options
    // some options are selected by default
  });

The second one draw charts using Chartist:

fetch("data/chartist.json")
  .then(response => response.json())
  .then(data => Object.keys(data).forEach(x => {
    // draw charts using Chartist
    const chart = new Chartist.Line(`#${x}`, { "series": data[x] });
    // add event handler to the charts
    chart.on("created", () => {
      // get values selected in the first fetch and use it
    });
  }));

I have overall working code, but it fails when the code (located in the second fetch) that get the selected value is executed before the select element (build in the first fetch) is ready.

I understand this is related to asynchronous programming, but I did not manage to implement a “good” solution by reading related posts (e.g. on async, await, promise).

I only found “bad” solutions, e.g.

  • Nest the second fetch in the first one: this waste time by not fetching data/chartist.json asynchronously. I only need to wait (if needed) at the step where I get the selected values.
  • Add a timeout (ditto).

Also, I tried (without success) to extract the event handler from the second fetch. I guess (not sure if this is better/needed) I could then let both fetch to run asynchronously and wait for the event handler only.

How can I fetch for select to be ready without wasting unecessary time?

Recursive approach to Persistent bugger problem returns undefined

I’ve been trying to solve the following problem in codewars using recursion:

Write a function, persistence, that takes in a positive parameter num and returns its multiplicative persistence, which is the number of times you must multiply the digits in num until you reach a single digit.
For example (Input –> Output):

39 --> 3 (because 3*9 = 27, 2*7 = 14, 1*4 = 4 and 4 has only one digit)
999 --> 4 (because 9*9*9 = 729, 7*2*9 = 126, 1*2*6 = 12, and finally 1*2 = 2)
4 --> 0 (because 4 is already a one-digit number)

Here’s what I’ve tried:

var numOfIterations = 0;
function persistence(num) {
   //code me
  var i;
  var digits=[];
  var result = 1;
  if (num.toString().length==1) {
    return numOfIterations;
  } else {
      numOfIterations++;
      digits = Array.from(String(num), Number);
      for (i=0;i<digits.size;i++) {
        result=result*digits[i];
      }
      persistence(result);
    }
}

But for some reason, instead of returning the number of iterations, it returns undefined. I’ve been told that I’m not using recursion correctly, but I just can’t find the problem.