jagi / meteor-astronomy

Model layer for Meteor
https://atmospherejs.com/jagi/astronomy
MIT License
604 stars 67 forks source link

Null on insert document into collection #56

Closed andrerfneves closed 9 years ago

andrerfneves commented 9 years ago

Great package. Seems to be working wonderfully in my project up to right now. I'm not quite sure of what I'm doing wrong but if anyone could help me out that'd be great.

This is going to seem like a very long issue but it's really just a lot of snippets of code. I basically have a simple Add Question page to that calls the /question/save Meteor Method on the server after validating and then inserts the document in the collection. For some reason, some of my fields (2 selects, 1 textarea and 1 input) come back as null. Not always the same one too (which makes things worst). I know the method is being called and a document is created (good sign) and I know the jQuery for querying the data from the form is sound. I'm just not sure what is going wrong.

<!-- Section of addQuestionAdmin Template -->
{{#with question}}
<div class="field">
    <label>Texto da Questão</label>
    <textarea rows="4" placeholder="Escreva a questão aqui..." type="text" value="{{text}}" id="text"></textarea>
</div>
<div class="inline fields">
    <div class="four wide field">
        <label>Resposta</label>
        <select class="ui dropdown" id="answer" value="{{answer}}">
            <option value="">Resposta</option>
            <option value="A">A</option>
            <option value="B">B</option>
            <option value="C">C</option>
            <option value="D">D</option>
        </select>
    </div>
    <div class="six wide field">
        <label>Prova</label>
        <input placeholder="Prova" type="text" id="prova" value="{{prova}}">
    </div>
    <div class="six wide field">
        <label>Área</label>
        <select class="ui dropdown" type="text" id="materia" value="{{materia}}">
            <option value="">Área da questão</option>
            <option value="0">Ética</option>
            <option value="1">Filosofia</option>
            <option value="2">Constitucional</option>
            <option value="3">Direitos Humanos</option>
            <option value="4">Direito Internacional</option>
        </select>
    </div>
</div>
<br>
<div class="right field">
    <div class="ui button green" type="button" name="save">Adicionar Questão</div>
{{/with}}

I then have a simple events page on the template

Template.addQuestionAdmin.events({
    'focus .field': function(e, tmpl) {
        var question = this;

        var text = $('#text').val();
        var answer = $('#answer').val();
        var prova = $('#prova').val();
        var materia = $("#materia").val();

        question.set('text', text);
        question.set('answer', answer);
        question.set('materia', materia);
        question.set('prova', prova);

        question.validate(text, answer, materia, prova);
    },
    'click [name=save]': function(e, tmpl) {
        var question = this;

        if (question.validate()) {
            Meteor.call('/question/save', question, function(err) {
                if (!err) {
                    Router.go('/admin');
                } else {
                    question.catchValidationException(err);
                }
            });
        }
    },

});

I also have the /question/save method on the server.

Meteor.methods({
    '/question/save': function(question) {
        if (question.validate()) {
            question.set('author', Meteor.userId());
            question.save();
            return question;
        }

        question.throwValidationException();
    }
})

Here's my collection

// Create global Mongo collection.
Questions = new Mongo.Collection('questions');

// Create global class (model).
Question = Astro.Class({
    name: 'Question', // Name model.
    collection: Questions, // Associate collection with the model.
    transform: true, // Auto transform objects fetched from collection.
    fields: {
        text: 'string',
        answer: 'string', // Define "title" field of String type.
        prova: 'string',
        materia: 'string',
        author: 'string',
    },
    behaviors: ['timestamp'] // Add "timestamp" behavior that adds "createdAt" and "updatedAt" fields.
});

Here's my router:

Router.route('/add-question', {
    name: 'addQuestionAdmin',
    data: function() {
        return {
            question: new Question()
        }
    }
});

It should be simple. I don't understand why the data isn't coming through. Through using Mongol all I can see on the db that some values get the data, some get null. They interchange, sometimes getting the first two fields and then the next try only gets the last 2 selects. It's fucking with my brain. What am I doing wrong!?

Any help would be appreciated. Thanks in advance!

lukejagodzinski commented 9 years ago

First of all, if it goes about the form, there is no value attribute in the SELECT element. You should use the selected attribute on the OPTION element instead.

It's hard to tell what is wrong without a reproduction. Could you create repo on GitHub that shows this situation? For me, everything looks properly.

andrerfneves commented 9 years ago

Hm, turns out all I had to do was split these up into individual calls

var text = $('#text').val();
question.set('text', text);

var answer = $('#answer').val();
question.set('answer', answer);

var prova = $('#prova').val();
question.set('prova', prova);

var materia = $("#materia").val();
question.set('materia', materia);

instead of the way before. Not quite sure why it works as such, but at least the data is coming through properly now.

And I was using a focus event on a field, I should've been using a change inputevent.

lukejagodzinski commented 9 years ago

I think the problem was using the focus event and trying to set all the fields at once in one event. In fact it would be better if you do it the way I did it in the example.

Having the id attribute of the input named the same as the field of the model you can just set a single field on each change event. You can also validate only this field or entire document if you wish.