17

I'm trying to get an ElementHandle's class name using Puppeteer... is it possible? Am I using the wrong approach? In this jsBin is part of my code, so you can understand what I am trying to achieve.

CriticalCssPlugin.prototype.load = function( page, src ) {
  return page.goto( src, { waitUntil: 'networkidle2' } )
    .then( () => {
      return page
        .$$( '*' )
        .then( elements => {
          return Promise.all( elements.map( element => {
            return element.boundingBox()
          } ) )
            .then( positions => {
              let visible = positions.filter( ( rect, index ) => {
                if ( !rect ) {
                  return rect
                }

                rect.element = elements[ index ]

                return this.isAnyPartOfElementInViewport( rect, page.viewport() )
              } )

              this.getClasses( visible )
            } )
        } )
    } )
}

CriticalCssPlugin.prototype.getClasses = function( visibles ) {
  Promise.all( visibles.map( visible => {
    return visible.element.getProperty( '' )
  } ) )
    .then( classes => {
      console.log(classes);
    } )
}

CriticalCssPlugin.prototype.isAnyPartOfElementInViewport = function( rect, viewport ) {
  const windowHeight = viewport.height
  const windowWidth = viewport.width
  const vertInView = ( rect.y <= windowHeight ) && ( ( rect.y + rect.height ) >= 0 )
  const horInView = ( rect.x <= windowWidth ) && ( ( rect.x + rect.width ) >= 0 )

  return ( vertInView && horInView )
}

https://jsbin.com/kuzejoluji/edit?js,output

Thank you :D

Gabriel Bueno
  • 480
  • 1
  • 4
  • 17

6 Answers6

23

Going to drop this here since this page is currently first result searching for "elementhandle class name"

From the docs, you should just be able to the following

const el = await page.$('.myElement')
const className = await el.getProperty('className')

// alternatively,
// page.$('.myElement')
//    .then(el => el.getProperty('className'))
//    .then(className => ... )
jimmyjoy
  • 246
  • 2
  • 3
  • 11
    In newer APIs you also need to call `jsonValue()` because `getProperty()` returns a JSHandle (see [docs](https://pptr.dev/#?product=Puppeteer&version=v5.5.0&show=api-elementhandlegetpropertypropertyname)). To get the class: `const className = await (await el.getProperty('className')).jsonValue()` – Luka Kralj Jun 09 '21 at 17:58
10

jimmyjoy's answer is right but this may help others use the elementHandle

  page.$(el) // This grabs the element (returns a elementHandle)
    .then((el) => el.getProperty("className")) // Returns a jsHandle of that property
    .then((cn) => cn.jsonValue()) // This converts the className jsHandle to a space delimitedstring       
    .then((classNameString) => classNameString.split(" ") // Splits into array
    .then((x) => console.log(x)

Which would log an array of classes

Note: when i tried to do a .split on the end of jsonValue() it didn't work as i believe the promise isn't resolved at that point so cn.jsonValue().split(" ") wont work


References

List of properties on elements

Puppeteer docs for ElementHandle

Daniel
  • 329
  • 2
  • 9
5

I found a solution that helps in parts, but it was good enough to me. I've got the class name acessing ElementHandle._remoteObject.description. Hope this helps someone.

Gabriel Bueno
  • 480
  • 1
  • 4
  • 17
  • 1
    After reading your post, `ElementHandle._remoteObject.value` is what ended up working perfectly for me, in my Puppeteer scripts. Thank you! – Coolio2654 Sep 06 '19 at 15:12
4

you can get the element variable and use evaluate function like that:

const element = await page.$(".some-class"); // for ids you can write "#some-id"
const className = await page.evaluate(el => el.className, element);
console.log('className', className) // here you can get the class name
Muho
  • 3,188
  • 23
  • 34
2

I use this function

// JS
export async function elementHasClass(el, className) {
  const classNames = (
    await (await el.getProperty('className')).jsonValue()
  ).split(/\s+/);

  return classNames.includes(className);
}

// TS
export async function elementHasClass(
  el: ElementHandle,
  className: string,
): Promise<boolean> {
  const classNames = (
    await (await el.getProperty('className')).jsonValue<string>()
  ).split(/\s+/);

  return classNames.includes(className);
}
0

This is what i did:

let posts = await page.$$(".postContainer .upvote");

for (let i = 0; i < posts.length; i++) {
// log class name
        console.log(await (await posts[i].getProperty('className')).jsonValue());

// click upvotes on posts
        await codes[i].click();
    }
Abdul.Moqueet
  • 902
  • 12
  • 19