Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No bind function error #161

Closed
elantion opened this issue May 11, 2015 · 8 comments
Closed

No bind function error #161

elantion opened this issue May 11, 2015 · 8 comments

Comments

@elantion
Copy link

I am making a new form with this code:

/* add article */
router.get('/add', csrfProtection, function(req, res) {
    var add_form = forms.create({
        title: fields.string({ required: true }),
        content: fields.string({ required: validators.required('请输入内容') }),
        csrfToken:forms.widgets.hidden({required:true})
    }).bind({ fields:{ csrfToken: req.csrfToken() }});//line 34
    add_form.toHTML();
    res.render('article/add',{
        add_form:add_form
    });
});

But it turns out a "no bind function error":

TypeError: undefined is not a function
   at /Users/jamesying/Desktop/lc/node_modules/forms/lib/forms.js:36:47 
   at Array.forEach (native)
   at Object.f.bind (/Users/jamesying/Desktop/lc/node_modules/forms/lib/forms.js:34:35)
   at /Users/jamesying/Desktop/lc/routes/articles.js:25:8
   at Layer.handle [as handle_request] (/Users/jamesying/Desktop/lc/node_modules/express/lib/router/layer.js:82:5)
   at next (/Users/jamesying/Desktop/lc/node_modules/express/lib/router/route.js:110:13)
   at csrf (/Users/jamesying/Desktop/lc/node_modules/csurf/index.js:97:5)
   at Layer.handle [as handle_request] (/Users/jamesying/Desktop/lc/node_modules/express/lib/router/layer.js:82:5)
   at next (/Users/jamesying/Desktop/lc/node_modules/express/lib/router/route.js:110:13)
   at Route.dispatch (/Users/jamesying/Desktop/lc/node_modules/express/lib/router/route.js:91:3)

But I actually can find the bind function in the source code.

Using this code dosen't work too:

    var loginForm = forms.create({
         username: fields.string({ required: validators.required('xxxx') }),
         password: fields.string({ required: validators.required('xxxx') }),
        csrfToken: widgets.hidden({
            required: true,
            value: req.csrfToken()
        })
    });

relate on another issue #82

@ljharb
Copy link
Collaborator

ljharb commented May 11, 2015

OK, so - widgets are meant to be used in toHTML, but not in forms.create- that only takes fields. bind is not a function on widgets, only on fields.

In this case, what you want is fields.string({ required: true, widget: widgets.hidden() }). There's not a fields.hidden because "hidden" is an attribute of the widget, not the field itself.

@elantion
Copy link
Author

Yes, I change the code with:

/* add article */
router.get('/add', csrfProtection, function(req, res) {
    var csrfToken = req.csrfToken();
    var add_form = forms.create({
        title: fields.string({ required: true }),
        content: fields.password({ required: validators.required('请输入内容') }),
        csrfToken:fields.string({ required: true, widget: widgets.hidden(),value: csrfToken})
    }).bind({ fields:{ csrfToken: csrfToken }}).toHTML();
    console.log(csrfToken);
    res.render('articles/add',{
        add_form:add_form
    });
});

It's pass without error.But the problem is there is no value attribute there. Have I forget something?
The console print the csrfToken, It's mean csrf protection is ok.

As my code before, I can't use hidden widget. Maybe you should change the readme.md, because it said there is a hidden widget.

thanks again.

@ljharb
Copy link
Collaborator

ljharb commented May 11, 2015

The value generally comes with ".bind", not in the field definition itself.

There is a hidden widget, but widgets aren't fields. I'll be happy to review a PR if you have an idea how to improve the docs!

@elantion
Copy link
Author

I use symfony framework before, It has a really good idea about form.
example( I haven't write php code from a long time ago, ignore the syntax mistake.);
1, create a form in controller

        $form = $this->createFormBuilder($task)
            ->add('task', 'text')
            ->add('dueDate', 'date')
            ->add('save', 'submit', array('label' => 'Create Task'))
            ->getForm();

2, add attribute in the fields.

        $form = $this->createFormBuilder($task)
            ->add('task', 'text')
            ->add('dueDate', 'date', array('attr'=>array('value'=>$csrfToken, 'class'=>'test')))
            ->add('save', 'submit', array('label' => 'Create Task'))
            ->getForm();

3, If you don't like writing php code, you can do it in Twig template also, like this:

{{ form(form, {'attr': {'value': 'csrfToken'}}) }}

Almost everything in field are attributes, It can easily add strange things in it. So frontend developer love this idea very much(Yes, I love it.).
And now, I love node.js. So I want to find something similar with symfony form builder. Because form building is a very very complicate task.

@ljharb
Copy link
Collaborator

ljharb commented May 11, 2015

I'm familiar with PHP and symfony, but that's not the pattern we're going for here.

The idea here is that you create the form and persist it across requests - and in each request and/or render, you use .bind to attach the values you want.

JS is a different language, shared mutable state is poison, and PHP patterns aren't often the ideal patterns to use in JS.

@elantion
Copy link
Author

Yes, I agree with you. Nodejs only have a thread. It's doesn't like PHP can have a lot of threads for a lot of users. So I am getting frustrating with nodejs. The logic is so complicate for me.

Get back to the issue I still can't get the value attribute, Can you give me a example?
I try this:

/* add article */
router.get('/add', csrfProtection, function(req, res) {
    var csrfToken = req.csrfToken();
    var add_form = forms.create({
        title: fields.string({ required: true }),
        content: fields.password({ required: validators.required('请输入内容') }),
        csrfToken:fields.string({ required: true, widget: widgets.hidden()})
    }).bind({ fields:{ csrfToken: {value: csrfToken} }}).toHTML();
    console.log(csrfToken);
    res.render('articles/add',{
        add_form:add_form
    });
});

It does't work too.
thanks.

@ljharb
Copy link
Collaborator

ljharb commented May 11, 2015

PHP usually has one thread too. It just has one per request, instead of one for everything.

You want to create add_form outside of the route handler. Then, do the .bind in the handler. Also, .bind({ fields: { csrfToken: csrfToken } })

@elantion
Copy link
Author

Maybe I have read a bad translated book.
Thank you very much.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants