Multiple Choice Questionnaire Using Checkboxes and Computed Properties in Ember.js - ember.js

Hi there SO community,
I'm new to development and have just recently begun learning Ember.js. As part of the Ember-Rails app that I'm building, I need to create a multi-step, multiple choice questionnaire. I've been stuck on a particular issue which I have not been able to find a solution for online.
You see, I have created a computed property, responseOptions, in my Questions1Controller. responseOptions is an array of multiple choice responses to the given question. Each question is a record in a questions table, and each multiple choice response is represented by a column on the questions table. I created the computed property responseOptions in order to display an array of checkboxes.
The problem that I am having is that I cannot pass the value of the selected array element, represented by a checked checkbox, to the Questions1Controller in order to create a new answer record. I am able to access the other properties of my questions records in the Questions1Controller, just not the computed property. I have included my Questions1Controller, along with the relevant template, below:
Questions1Controller:
RailsCharts.Questions1Controller = Ember.ObjectController.extend({
actions: {
createAnswer: function(){
var user_id = 5;
var question_id = this.get('hard_coded_id');
var selected_response = this.get('selected_answer');
var newAnswer = this.store.createRecord('answer', {
userId: user_id,
questionId: question_id,
answer: selected_response
});
newAnswer.save();
}
},
responseOptions: function () {
var option1Val = this.get('option_1');
var option2Val = this.get('option_2');
var option3Val = this.get('option_3');
var option4Val = this.get('option_4');
var option5Val = this.get('option_5');
var arryOfOptions = [option1Val, option2Val, option3Val, option4Val, option5Val];
var arryOfOptionsFiltered = [];
for (var i=0; i<arryOfOptions.length; i++){
arryOfOptions[i] !== null && arryOfOptionsFiltered.push(arryOfOptions[i]);
}
return arryOfOptionsFiltered;
}.property('arryOfOptionsFiltered.#each')
});
Questions/1 Template:
<h1>Question 1</h1>
<div class='form-group'>
<div class='wording'>
{{wording}}
</div>
<hr>
<div class='answer'>
{{#each responseOptions}}
<label class="checkbox inline">
{{input type='checkbox' checked=selected_answer}}{{this}}
</label>
</br>
{{/each}}
</div>
{{outlet}}
</div>
<button class="btn btn-default" {{action "createAnswer"}}>Submit</button>
Any help would be greatly appreciated.

You can't just have one "selected_answer" be the value of the checkbox. It needs to be some kind of array to get all of the values.
An example might be having a 'selected' property on the actual option object itself. Your model might look like this (although you can add selected at other points)
App.Questions1Route = Ember.Route.extend({
model: function(){
return Ember.Object.create({
option_1: Ember.Object.create({value: "x", selected: false}),
option_2: Ember.Object.create({value: "y", selected: false}),
option_3: Ember.Object.create({value: "z", selected: false}),
option_4: Ember.Object.create({value: "a", selected: false}),
option_5: Ember.Object.create({value: "b", selected: false})
});
}
});
Then your template would be:
<div class='answer'>
{{#each responseOptions}}
<label class="checkbox inline">
{{input type='checkbox' checked=this.selected}}{{this.value}}
</label>
</br>
{{/each}}
</div>
Let me know if that helps.
JS bin for you to play with:
http://emberjs.jsbin.com/masepexa/4/edit

Related

I'm struggling to create a new comment the correct way on the frontend ember

I am trying to create a comment with this addComment action where I want to use the input text as the comment text and do a save to create the comment.
I couldn't connect the input box to comment.body because the position of this code does not have the comment model available.
I created a body field on the item model so I connect item.body to the text box and then use this as the comment.body when creating the comment which seems very wrong. Does anyone have any suggestions as to how to do this the correct way?
<form class="comments-list__add-comment add-comment" action="">
{{input type="text" class="add-comment__input" name="" value=item.body placeholder="Please add a comment"}}
<button {{action "addComment" item}} type="button" class="btn add-comment__submit" name="button">Add comment</button>
</form>
addComment(item){
const plan = item.get('plan');
const text = this.get('item.body');
const currentUserName = plan.get('appConfig.currentUser');
const currentUserId = plan.get('appConfig.currentUserId');
const itemid = item.id;
if(text.trim() !== ''){
let comment = this.get('item.store').createRecord('comment', {
body: text,
createdAt: new Date(),
commentableId: itemid,
commentableType: 'Plan',
unread: true,
commenterName: currentUserName,
commenterId: currentUserId
});
item.get('comments').pushObject(comment);
comment.save();
item.set('displayAddCommentForm', false);
this.set('item.body', '');
}
},
You can create a comment record in your route and assign it to a controller property. Then you can bind your template to the controller's comment property, like this:
route
export default Ember.Route.extend({
setupController(controller, model) {
this._super(...arguments);
controller.set('comment', this.store.createRecord('comment');
}
});
template
{{input value=comment.body}}
Then, in your Route's save method:
let comment= this.controller.get('comment');
// the remainder of your save should follow...
// At this point, comment.body should have the text entered by user

How to display post's delete button for only post's author in Ember.js

Hello I've been stuck for days how to display a post's delete button only for the post's author in Ember.js (I'm using ember-cli to build this). I don't know where to put the logic of "When hovering a post (list), if the post's author is equal to currently logged in user, then display the delete button" I am lost. Please help me.
in template app/templates/posts.hbs
{{#each}}
<div class="eachPost">
{{#view 'posts'}}
<div class="postProfilePhoto">
{{#link-to 'users' }}
<img src="" alt="Profile Photo">
{{/link-to}}
</div>
<div class="eachPostContent">
<p class="postAuthor"><strong>{{user.id}}</strong></p>
<p class="postContent">{{body}}</p>
<span class="timePosted"><em>somtimes ago</em></span>
{{#if view.entered}}{{#if isAuthor}}
<a class="deletePost" {{action "removePost" this}}>Delete</a>
{{/if}}{{/if}}
</div>
{{/view}}
</div>
{{/each}}
in views app/views/posts.js
var Posts = Ember.View.extend({
classNames: ['eachPostContent'],
mouseEnter: function(event){
this.set('entered', true);
this.get('controller').send('isAuthor', this.get('post').user);
},
mouseLeave: function(){
this.set('entered', false);
}
});
export default Posts;
in controller app/controllers/posts.js
var PostsController = Ember.ArrayController.extend({
...
isAuthor: function(user){
if(this.get('session').user !== null && user === this.get('session').user){
return true;
} else {
return false;
console.log('You are not author');
}
}
}
});
export default PostsController;
SOLVED
in app/templates/posts.hbs
{{#each itemController="post"}}
<div class="eachPost">
created app/controllers/post.js
var PostController = Ember.ObjectController.extend({
isAuthor: function(){
return this.get('user') === this.get('session').user;
}.property('user')
});
export default PostController;
delete following code from app/views/posts.js
this.get('controller').send('isAuthor', this.get('post').user);
and deleted isAuthor function from app/controllers/posts.js
As mentioned above, you'll want to use an itemController
var PostsController = Ember.ArrayController.extend({
itemController:'post',
...
});
And then in the itemController you will create a computed property that checks the user id against the author id of the post
var PostController = Ember.ObjectController.extend({
isAuthor: function(){
//assuming the user property exists on an individual post model
return this.get('user') === this.get('session').user;
}.property('user')
})

List of checkboxes values as array like Ember.Select (multiple)

Is there a way to get the data of a list of checkboxes in Ember as an array of id's?
In my app I want to make a new Site. I made a route to /sites/new to show a form with fields to add a Site.
This is my Model:
App.Site = DS.Model.extend({
name : DS.attr('string'),
languages: DS.hasMany('App.Language')
});
App.Language = DS.Model.extend({
name : DS.attr('string')
});
This is my Controller:
app.SitesNewController = Em.ObjectController.extend({
needs : [ 'languages' ],
name: null,
languages: null,
createSite : function() {
// Get the site name
var name = this.get('name');
var languages = this.get('languages');
console.log(name,description,languages);
// Create the new Site model
app.Site.createRecord({
name : name,
languages : languages
});
// Save the new model
this.get('store').commit();
}
});
This is (part of) my SitesNewView:
{{#each controllers.languages}}
<label class="checkbox">
{{view Ember.Checkbox checkedBinding="languages"}}
{{ name }}
</label>
{{/each}}
<button {{ action "createSite" }}>Save</button>
In my console languages is null. How do I get an array of language-id's out of this.get('languages')?
UPDATE
I mean something like an Ember.Select with attribute multiple=true, like this: {{view Ember.Select selectionBinding="languages" contentBinding="controllers.languages" optionValuePath="content.id" optionLabelPath="content.name" multiple="true"}}
Take a look to the jsfiddle that I quickly created.
This may not be the best solution but at least it should help you.

How to remove an object from the controller when an Ember.Checkbox is checked

Currently I'm playing with the latest ember.js release and I'm building a simple "add username / remove username" hello world app. So far I can add a user (with the controller method below). I also have a checkbox in the html that when clicked should remove the user but ... right now I can only get the bool value of the checkbox to pass off. Instead I need the username to look it up and remove it from the controller content.
How can I re-do the html / view code below so that I can pass off the actual username instead of the bool value?
Thank you in advance!
PersonApp.ModifyPersonCheckbox = Em.Checkbox.extend({
change: function(event) {
PersonApp.personController.removePerson(this.$().val());
},
});
PersonApp.personController = Em.ArrayProxy.create({
content: [],
createPerson: function(username) {
var person = PersonApp.Person.create({ username: username });
this.pushObject(person);
},
removePerson: function(username) {
person = this.content.findProperty('username', username);
this.removeObject(person);
}
});
the basic html below shows how my checkedBinding is wired up
<ul>
{{#each PersonApp.personController}}
<li {{bindAttr class="isActive"}}>
<label>
{{view PersonApp.ModifyPersonCheckbox checkedBinding="isActive"}}
{{username}}
</label>
</li>
{{/each}}
</ul>
You will need to set the content on the view showing the checkbox so that when the event is triggered, the context is passed. I believe this will work:
{{view PersonApp.ModifyPersonCheckbox contentBinding="parentView.content" checkedBinding="isActive"}}
Then, the event variable in the change function will have a context variable containing the record associated with that checkbox. Then you won't even need to search for it in the controller. You can also just bind the username, but this way is cleaner.
The final solution looks like the below (notice the contentBinding="this" addition to the markup)
PersonApp.ModifyPersonCheckbox = Em.Checkbox.extend({
content: null,
change: function(event) {
PersonApp.personController.removePerson(this.content);
},
});
PersonApp.personController = Em.ArrayProxy.create({
content: [],
createPerson: function(username) {
var person = PersonApp.Person.create({ username: username });
this.pushObject(person);
},
removePerson: function(person) {
this.removeObject(person);
}
});
<ul>
{{#each PersonApp.personController}}
<li {{bindAttr class="isActive"}}>
<label>
{{view PersonApp.ModifyPersonCheckbox contentBinding="this" checkedBinding="isActive"}}
{{username}}
</label>
</li>
{{/each}}
</ul>

Rendering multiple Models each containing multiple objects in Ember Js

I'm quite new to EmberJS. I am trying to render a simple hasMany modelisation.
My app is supposed to handle multiple tasks for multiple persons.
First, I have models:
App.Task = Em.Object.extend({
name: null
});
App.Person = Em.Object.extend({
firstname: null,
lastname: null,
avatar: null,
tasks:null,
});
A person can have multiple tasks. So my personsController works like this:
App.personsController = Em.ArrayController.create({
content: [],
tasks:[],
addPerson: function(){
var aPerson = App.Person.create({
firstname: this.firstname,
lastname : this.lastname,
avatar : this.avatar,
});
this.pushObject( aPerson );
}
My tasksController, wich will handle tasks jobs:
App.tasksController = Em.ArrayController.create({
content:[],
contentBinding: "App.personsController.tasks",
name:'',
removeTask: function(e){
this.removeObject( e.context );
},
addTask: function(e){
this.pushObject( App.Task.create({"name":this.name}) );
}
});
contentBiding seems to be one of the keys here. I want it to auto-bind to the tasks of the person I'm working on.
On the views side, just working on my Handlebars templates:
<script type="text/x-handlebars">
{{view Em.TextField valueBinding="App.personsController.firstname" placeholder="firstname" }}
{{view Em.TextField valueBinding="App.personsController.lastname" placeholder="lastname" }}
<button {{action "addPerson" target="App.personsController"}} class="btn btn-primary" >Ajouter un developpeur</button>
{{#each App.personsController}}
<div>
<h3>{{firstname}}{{lastname}}</h3>
{{view Em.TextField valueBinding="App.tasksController.name"}}
<button {{action "addTask" target="App.tasksController"}} >Add a task</button>
{{#each App.tasksController}}
{{view Em.TextField valueBinding="name" }}
<button {{action "removeTask" target="App.tasksController"}} >x</button>
{{/each}}
</div>
{{/each}}
</script>
So, when I'm adding a new person, everything works fine. But if I add a task, the task is added on each of the person's tasks in the view.
I'm afraid I'm making a conceptual mistake, and I can't find a good documentation about this kind of visualisation. I've seen examples of hasMany relations with ember.data, but I'd like first to understand properly what is going on here.
Your addTask function adds a new task to the array maintained within App.tasksController, but there is nothing binding these tasks to any instance of App.Person.tasks.
I suggest creating new View class with a binding to your tasksController and to a single App.Person instance. The personBinding of this view would be set inside of your outer {{#each}} loop. Have this view be responsible for rendering App.Person.tasks for a single person.
Change addTask in your controller to accept a reference to an App.Person as an argument, then add the task explicitly to that person's tasks array in the body of the function.