1

In my cake app I have a model called faqs, controller called faqs_controller & view called faqsindex.php.

I'm making a CMS so users can change the FAQs. The db table 'faqs' has 5 columns id, category, question, answer and number. "Number" is the order in which the FAQ's will appear.

The loop that lists all of the FAQs looks more or less like this:

<?php
foreach ($faqs as $faq):
<tr>
<td><?php echo $faq['Faq']['category']; ?></td>
<td><?php echo $faq['Faq']['number']; ?></td>
<td><?php echo $faq['Faq']['question']; ?></td>
<td><?php echo $faq['Faq']['answer']; ?></td>
</tr>
<?php endforeach; ?>

I want to make it so that the user can change the "number" cell from this screen, instead of going into a separate edit screen for each row and changing the number there.

You know, like how netflix's queue works, where the user can reorder it from the list, you don't have to click on the movie you want to see to change its order in your queue.

EDIT I set up edit in faqs_controller.php like this:

    function edit() {
       if(!empty($this->data)) {
          $this->Faq->saveAll($this->data['Faq']);
       }
       else {
          $this->data['Faq'] = Set::combine($this->Faq->find('all'), '{n}.Faq.id', '{n}.Faq');
       }
}

and in the index view I made a foreach that looks like this:

echo $form->create('Faq', array('action'=>'edit'));
foreach($this->viewVars['faqs'] as $key => $value) {
    echo 'id:'.$value['Faq']['id'];
    echo '<br/>question:'.$value['Faq']['question']; 
    echo $form->input('Faq.'.$key.'.number');
}

In this case the foreach goes round 8 times because there are 8 rows. If I submit them, I create 8 new rows & can't update existing rows.

-EDIT-

I changed the form echo here:

echo $form->input('Faq.'.$key.'.question',array('value'=>$value['Faq']['question']));

to prepopulate the form. What I can't figure out is how to update the proper row. If I submit the form I get 8 mysql queries like this:

INSERT INTO faqs (question) VALUES ('THE NEW QUESTION I JUST ADDED?') when I don't want an insert but an update.

2
  • Create a form, in your controller retrieve the FAQ objects associated with the submitted form fields, update their number property, and save the FAQ objects again. Is there another way? Commented Jul 23, 2011 at 0:28
  • I wasn't real clear with what I was trying to do, I'm trying to figure out how to do the update. Commented Jul 26, 2011 at 0:20

3 Answers 3

4
+50

Put each faq id inside your form?

echo $form->create('Faq', array('action'=>'edit'));
foreach($this->viewVars['faqs'] as $key => $value) {
    echo 'id:'.$value['Faq']['id'];
    echo '<br/>question:'.$value['Faq']['question']; 
    echo $form->hidden('Faq.'.$key.'.id', array('value' => $value['Faq']['id']));
    echo $form->input('Faq.'.$key.'.number');
}
Sign up to request clarification or add additional context in comments.

Comments

3

if you are using jquery: http://jqueryui.com/demos/sortable/ All the ordering is done on client side, you put the order value into hidden input and use javascript to change them according to user interaction. There's nothing to change on the server side script.

Edit:

echo $form->create('Faq', array('action'=>'edit'));
foreach($this->data['Faq'] as $key => $value) {
   echo 'id:'.$value['Faq']['id'];
   echo '<br/>question:'.$value['Faq']['question']; 
   echo $form->input('Faq.'.$key.'.number');
   echo $form->input('Faq.'.$key.'.id');
}
echo $form->end('Save');

and the controller:

function edit() {
   if(!empty($this->data)) {
      $this->Faq->saveAll($this->data['Faq']);
   }
   $this->data['Faq'] = Set::combine($this->Faq->find('all'), '{n}.Faq.id', '{n}.Faq');
}

unless you redirect them somewhere else after saving.

6 Comments

I don't really need them to be sortable like this, although it looks really cool and I can do this next. I'm totally happy with just being able to enter numbers for now. I did this, but it just inserts new rows instead of updating existing ones. I'll rewrite question.
I get "Invalid argument supplied for foreach()" on the loop. I can loop through the data if I change it to "foreach($this->viewVars['faqs']" as described above, but then I'm still stuck.
did you use the same edit() fucntion I wrote? what is the output of debug($this->data); when you put that line on the view?
blankness, nothingness. If I print_r $this I can see "data" is empty. I was just using viewVars because I could see it had the data I wanted.
hm.. that's weird, if you set $this->data in the controller, you can see it in the view.
|
1

If you're wanting to update a specific row with Cake it is as simple as setting the appropriate row ID in your saveAll() query.

function edit() {

    if (!empty($this->data)) {
        $this->Faq->saveAll($this->data['Faq'], array('conditions' => array('Faq.id' => $yourId)));
    }
    ...

}

This is telling Cake's ORM to save the information into the row only where Faq.id is equal to $yourId. If $yourId matches an existing ID in your table then that row should be updated.

Edit

You can put the id field into a hidden form element using CakePHP's FormHelper.

$this->Form->hidden('id', array('value' => $value['Faq']['id']));

4 Comments

where does $yourId come from though? I'm sorry if I seem thickheaded here I'm just having a hard time getting my head around this. I want the 8 form fields that come form the foreach to each have an id that matches the 'Faq.id'. I also want the forms to be prepopulated with whatever is already in there.
@pg You would have to supply that. Assuming since you're updating the record you've gathered the appropriate id. If you haven't then you should be able to add your id field to the database query that you use to populate the form inputs with the database record you're editing. Then simply include that ID in a hidden form input. The appropriate id will be transferred in $this->data['Faq']['id'] if setup correctly.
OK that's my question then. How do I include $yourId into the hidden form input? Should the input be input('Faq.'.$value['Faq']['id']'.number')?
thanks for your help I was able to work it out by combining all three answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.