I have a model. It contains a list of another model:
case class Account(
_id: ObjectId = new ObjectId,
name: String,
campaigns: List[Campaign]
)
case class Campaign(
_id: ObjectId = new ObjectId,
name: String
)
I have a form and action for display and creating new Accounts:
val accountForm = Form(
mapping(
"id" -> ignored(new ObjectId),
"name" -> nonEmptyText,
"campaigns" -> list(
mapping(
"id" -> ignored(new ObjectId),
"name" -> nonEmptyText
)(Campaign.apply)(Campaign.unapply)
)
)(Account.apply)(Account.unapply)
)
def accounts = Action {
Ok(views.html.accounts(AccountObject.all(), accountForm, CampaignObject.all()))
}
def newAccount = Action {
implicit request =>
accountForm.bindFromRequest.fold(
formWithErrors => BadRequest(views.html.accounts(AccountObject.all(), formWithErrors, CampaignObject.all())),
account => {
AccountObject.create(account)
Redirect(routes.AccountController.accounts)
}
)
}
Finally, here is my view for Accounts:
@(accounts: List[models.mongodb.Account], account_form: Form[models.mongodb.Account], campaign_list: List[models.mongodb.Campaign])
@import helper._
@args(args: (Symbol, Any)*) = @{
args
}
@main("Account List") {
<h1>@accounts.size Account(s)</h1>
<ul>
@accounts.map { account =>
<li>
@account.name
</li>
}
</ul>
<h2>Add a New Account</h2>
@form(routes.AccountController.newAccount()) {
<fieldset>
@inputText(account_form("name"), '_label -> "Account Name")
@select(
account_form("campaigns"),
options(campaign_list.map(x => x.name):List[String]),
args(
'class -> "chosen-select",
'multiple -> "multiple",
Symbol("data-placeholder") -> "Add campaigns",
'style -> "width:350px;"
): _*
)
<input type="submit" value="Create">
</fieldset>
}
}
The problem is when I submit this form, it submits it with a list of strings for the campaigns
field. This gives me a 400 error when I post the form submission.
I would like to either submit submit the form with a list of campaigns instead of strings or have the form submit with a list of strings, then process the strings into a list of campaigns in my controller. Which way would be better and how would I do it? Thanks!
I ended up making a temp form to hold the strings of the nested model. Then I converted those strings to model objects in my controller:
val accountTempForm = Form(
tuple(
"id" -> ignored(new ObjectId),
"name" -> nonEmptyText,
"campaigns" -> list(text)
)
)
def newAccount = Action {
implicit request =>
accountTempForm.bindFromRequest.fold(
formWithErrors => {
println("error")
Redirect(routes.AccountController.accounts)
//BadRequest(views.html.account.accounts(AccountObject.all(), formWithErrors, CampaignObject.all()))
},
account => {
val campaign_string_list = account._3
val campaign_list = campaign_string_list.map(x => CampaignObject.getOrCreateByName(x))
val new_account = Account.apply(account._1, account._2, campaign_list)
AccountObject.create(new_account)
Redirect(routes.AccountController.accounts)
}
)
}