purescript-simple-dom icon indicating copy to clipboard operation
purescript-simple-dom copied to clipboard

Link modification example doesn't work

Open codygman opened this issue 10 years ago • 9 comments

module Validator.Main where

import Control.Monad.Eff
import Data.DOM.Simple.Element
import Data.DOM.Simple.Window
import Data.DOM.Simple.Types
import Data.Traversable
import qualified Data.Array as A

modifyLinkTarget link = do
  attr <- getAttribute "href" link       -- attr = link.getAttribute("href")
  setAttribute "href" "#" link           -- link.setAttribute("href", "#")
  setAttribute "data-target" attr link   -- link.setAttribute("data-target", attr)
  return link

modifyLinks page = do
  links <- querySelectorAll "a" page      -- links = [HTMLElement]
  sequence $ A.map modifyLinkTarget links -- links.map(modifyLinkTarget)


main = do
  doc <- document globalWindow
  links <- querySelectorAll "a" doc      -- links = [HTMLElement]
  modifyLinks (links :: [HTMLElement])
  pure unit
cody@cody-XPS-L521X:~/programming/purescript/validator$ grunt
Running "psc:all" (psc) task
>> Error creating file dist/example.js
>> 
Warning: Error at src/Validator/Main.purs line 10, column 1 - line 16, column 1: 
Error in declaration modifyLinkTarget
No instance found for Data.DOM.Simple.Element.Element u11318 Use --force to continue.

Aborted due to warnings.

codygman avatar Jan 17 '15 06:01 codygman

You have to add a type signature. The compiler won't infer constraints so it gives you that error you got: https://github.com/purescript/purescript/wiki/Differences-from-Haskell#type-classes-and-type-inference

Also, your types don't line up in main. it should be: traverse modifyLinks links. For that matter, the last line of modifyLinks could be simplified to traverse modifyLinkTarget links. Or you could even make the whole function clearer with:

modifyLinks = querySelectorAll "a" >=> traverse modifyLinkTarget

joneshf avatar Jan 20 '15 13:01 joneshf

After reading your above link, I added a top level signature and got modifyLinkTarget to type check. Here is the full code along with my new error:

module Validator.Main where

import Control.Bind
import Control.Monad.Eff
import Data.DOM.Simple.Element
import Data.DOM.Simple.Window
import Data.DOM.Simple.Types
import Data.Traversable
import qualified Data.Array as A

modifyLinkTarget :: HTMLElement -> forall eff b. Eff (dom :: Data.DOM.Simple.Types.DOM | eff) HTMLElement
modifyLinkTarget link = do
  attr <- getAttribute "href" link       -- attr = link.getAttribute("href")
  setAttribute "href" "#" link           -- link.setAttribute("href", "#")
  setAttribute "data-target" attr link   -- link.setAttribute("data-target", attr)
  return link

modifyLinks = querySelectorAll "a" >=> traverse modifyLinkTarget

main = do
  doc <- document globalWindow
  -- links <- querySelectorAll "a" doc      -- links = [HTMLElement]
  -- modifyLinks (links :: [HTMLElement])
  -- traverse modifyLinks links
  pure unit

error:

Warning: Error at src/Validator/Main.purs line 18, column 1 - line 20, column 1: 
Error in declaration modifyLinks
No instance found for Data.DOM.Simple.Element.Element u11343 Use --force to continue.

Aborted due to warnings.

Is it because I need to add a top level signature to modifyLinks as well? I'm going to look at it more later, but appreciate any direction or help you can give me.

codygman avatar Jan 20 '15 22:01 codygman

Yep.

joneshf avatar Jan 20 '15 22:01 joneshf

I believe I have the right type now.

modifyLinks :: HTMLDocument -> forall eff b. Eff (dom :: Data.DOM.Simple.Types.DOM | eff) [HTMLElement] -- line 19
modifyLinks = querySelectorAll "a" >=> traverse modifyLinkTarget

Does this error mean I have to create an instance of traverse for Element HTMLDocument?

Warning: Error at src/Validator/Main.purs line 19, column 1 - line 20, column 1: 
Error in declaration modifyLinks
No instance found for Data.DOM.Simple.Element.Element Data.DOM.Simple.Types.HTMLDocument Use --force to continue.

I apologize if these questions are simple ones I should be able to figure out, I'm just having a hard time even after re-reading the relevant chapters in the purescript book. If you have any tutorials to recommend using traverse I'm guessing that would help me figure this problem out.

Thank you for your help and patience. Hopefully others will stumble onto this issue and it will answer their questions as well.

codygman avatar Jan 21 '15 04:01 codygman

No worries. You want something like this:

module Validator.Main where

import Control.Monad.Eff
import Data.DOM.Simple.Document
import Data.DOM.Simple.Element
import Data.DOM.Simple.Window
import Data.DOM.Simple.Types
import Data.Traversable
import qualified Data.Array as A

modifyLinkTarget :: forall eff. HTMLElement -> Eff (dom :: _ | eff) HTMLElement
modifyLinkTarget link = do
  attr <- getAttribute "href" link       -- attr = link.getAttribute("href")
  setAttribute "href" "#" link           -- link.setAttribute("href", "#")
  setAttribute "data-target" attr link   -- link.setAttribute("data-target", attr)
  return link

modifyLinks :: forall eff. HTMLElement -> Eff (dom :: _ | eff) [HTMLElement]
modifyLinks page = do
  links <- querySelectorAll "a" page      -- links = [HTMLElement]
  sequence $ A.map modifyLinkTarget links -- links.map(modifyLinkTarget)


main = do
  doc <- document globalWindow
  links <- querySelectorAll "a" doc      -- links = [HTMLElement]
  traverse modifyLinks links
  pure unit

joneshf avatar Jan 21 '15 05:01 joneshf

Code compiling, but no links are being found:

module Validator.Main where

import Control.Monad.Eff
import Debug.Trace
import Data.DOM.Simple.Document
import Data.DOM.Simple.Element
import Data.DOM.Simple.Window
import Data.DOM.Simple.Types
import Data.Traversable
import qualified Data.Array as A

modifyLinkTarget :: forall eff. HTMLElement -> Eff (dom :: _ | eff) HTMLElement
modifyLinkTarget link = do
  attr <- getAttribute "href" link       -- attr = link.getAttribute("href")
  setAttribute "href" "#" link           -- link.setAttribute("href", "#")
  setAttribute "data-target" attr link   -- link.setAttribute("data-target", attr)
  return link

modifyLinks :: forall eff. HTMLElement -> Eff (dom :: _ | eff) [HTMLElement]
modifyLinks page = do
  links <- querySelectorAll "a" page      -- links = [HTMLElement]
  sequence $ A.map modifyLinkTarget links -- links.map(modifyLinkTarget)

main = do -- strangely I need the do here or I get an error
  doc <- document globalWindow
  links <- querySelectorAll "a" doc
  trace $ "number of links: " ++ (show $ A.length links)



<html>
  <head>
    <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
    <meta content="utf-8" http-equiv="encoding">
    <title>Example purescript app</title>
  </head>
  <body>
    <script type="text/javascript" src="dist/example.js"></script>
    <a href="">test link</a>
  </body>
</html>

Console:

"number of links: 0"

Why aren't any links being matched?

codygman avatar Jan 21 '15 21:01 codygman

Oh, it's because I had the link under the javascript :)

codygman avatar Jan 21 '15 21:01 codygman

With the following html, nothing happens (the link isn't modified):

<html>
  <head>
    <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
    <meta content="utf-8" http-equiv="encoding">
    <title>Example purescript app</title>
  </head>
  <body>
    <a href="">test link</a>
    <script type="text/javascript" src="dist/example.js"></script>
  </body>
</html>

codygman avatar Jan 21 '15 21:01 codygman

Is your actual code traverseing anything? If it's like above, then you haven't told it do modify anything.

joneshf avatar Jan 21 '15 22:01 joneshf