DAB0mB / Appfairy

A CLI tool to Migrate a Webflow project into a React app
MIT License
286 stars 39 forks source link

unable to inject af-el components #10

Closed ebalder closed 3 years ago

ebalder commented 5 years ago

Hi Eytan, first of all, great work here, this concept can allow people to save so much time.

In the latest version (0.7.3), the views generated by the appfairy command are a bit different and I don't know how to use child components, could you provide a snippet as an example of how to use it? if you do, I can send you a PR with an up to date example.

The HTML bit exported from webflow is as follows. I'll call it MainView

<body class="body">
  <div af-el="prod-form" af-sock="prod-form" class="div-block-2">
    <div class="w-form">
      <form id="wf-form-Producdt-Identification-Form" name="wf-form-Producdt-Identification-Form" data-name="Producdt Identification Form">
          <label for="name">Product Name</label>
          <input type="text" class="w-input" maxlength="256" name="name" af-sock="prod-name" data-name="Name" id="name" required="">
          [...]
          <input type="submit" value="Submit" data-wait="Please wait..." af-sock="prod-submit" class="w-button">
</form>
      <div class="w-form-done">
        <div>Thank you! Your submission has been received!</div>
      </div>
      <div class="w-form-fail">
        <div>Oops! Something went wrong while submitting the form.</div>
      </div>
    </div>
  </div>

In the generated MainView, in the place of the div with af-el=prod-form it generates some lines like these

<div className="af-class-body">
  <ProdFormView.Controller-af-sock-prod-form />
       {/* [if lte IE 9]><![endif] */}
</div>

Then in MainController I did the following, according to the 'prefetch' tutorial

import React from 'react';
import ProdFormController from './ProdFormController';
import MainView from '../views/MainView';

export default (params) => (
  <MainView>
      <prod-form {...params} />
  </MainView>
);

when running a project with this view and controller renderd by the Router, I get an error like this:

TypeError: Property property of MemberExpression expected node to be of a type ["Identifier","PrivateName"] but instead got "StringLiteral"

Trying to find out what's wrong, I saw the view on your example, and it's a bit different, there the af-el element would be parsed as

<div className="__af-container-2 __af-w-container">
            <h1 className="__af-heading-3">Registered Immigration Agent in Sydney, Australia</h1>
            {proxies['contact-form'] && <ContactFormView.Controller {...proxies['contact-form']}>{proxies['contact-form'].children}</ContactFormView.Controller>}
</div>

It doesn't look like something generated by the current version.

Could you guide me on how the new parsed views are supposed to be used?

Thanks! keep up the great work!.

jayb967 commented 5 years ago

Did you make your ProdFormController and wrap it in the view? Like: class ProdFormController extends React.Component { state = {}

render() { return <ProdFormView> <name onChange={this.setName} /> <submit onClick={this.submit} /> </ProdFormView>

} }

Geofflew commented 5 years ago

I get the same error when af-el and af-sock are assigned to the same Div. Got the error even with a clean project trying to follow the original tutorial video. Couldn’t figure out how to fix it though

ebalder commented 5 years ago

Did you make your ProdFormController and wrap it in the view? Like: class ProdFormController extends React.Component { state = {}

render() { return <ProdFormView> <name onChange={this.setName} /> <submit onClick={this.submit} /> </ProdFormView>

} }

I did, but that's not relevant to the issue because the error is that the code generated tries to inject that controller in a way that's just not valid.

My workaround was to remove all component calls like ProdFormView.Controller-af-sock-prod-form and replace them with ProdFormView.Controller. But it's not optimal to work like that and I'm not completely sure it doesn't break some functionality.

jayb967 commented 5 years ago

Yeah you're right, I didn't catch that part. I have done the same, I was fixing a view-second-element-input af-el that would convert to ViewSecondElement.Controller-input on my view to ViewSecondElementInput.Controller It might be or might not have to do the same but I actually had to rename some of my af-sock's and af-el's to something else until they converted correctly and didn't have to mess with that file every time I updated. Also have to make sure that you don't have an af-el inside another af-el as that also causes issues. I can actually pass in divs into a af-sock as it does render the children into that, also each element should either be af-el OR af-sock.

ebalder commented 5 years ago

ah, yes, I tried making af-el a partent of the af-sock with the same name and it worked. It's so weird that you cannot nest af-el's, I guess we can't generate separate views for some components ):

jayb967 commented 5 years ago

What I figured is that you can definitely nest af-els. But the "nesting" would have to be in the React code. import AfElSecondController from './controllers/AfElSecondController'; class AfElFirstController...{ render(){ return( <AfElSecondController/> ) } }

Say you want to make any other component in Webflow like a card that want to put that in a grid (for collections etc). I'll create a new page in webflow, make the element (card), then give the main card the af-el of say "product-card" and name all the different components with their af-socks. In say the second af-el "AfElSecondController" code I do:

import ProductCardController from './controllers/ProductCardController'; class AfElSecondController...{ render(){ const arrayOfCards = [<ProductCardController {propsIWantToPassToEachCard} />] return( <div style={{ position: 'relative', display: 'flex', overflowX: 'scroll', scrollBehavior: 'smooth' }}> {arrayOfCards} </div>

)} } Inside my ProductCardController I have: import ProductCardView from './views/ProductCardView'

class ProductCardController extends Component{ render(){ const { first, buttonCallback } = this.props return( <ProductCardView> <myfirst-af-socket> //value i want to add on socket {first} </myfirst-af-socket> <mybutton-af-socket onClick={() => buttonCallback()}>

</ProductCardView> ) } }

ebalder commented 5 years ago

this is not related to the issue being reported, which is a parsing problem (in the generated views), where the view, just by being imported, makes the entire compilation fail. The workaround was avoiding af-el and af-sock in the same element (doing af-el as a child of af-sock instead)

because I needed something to inject a component to, not only field values. this use case is documented as working and broke at some point.

DAB0mB commented 3 years ago

af-el and af-sock can now co-exist. I fixed that.