How to choose only one radio button using AngularJS - angularjs

I've tried searching for questions similar to mine, only to find out that our circumstances aren't the same. So I'm posting this here.
I'm trying to create a list of questions where the methods of selection depends on the question, so question #1 can have radio buttons, question #2 can have checkboxes, and so on. One set lets the user choose the answer using radio buttons, however they're behaving like checkboxes (minus the unchecking). Am I missing something?
Below is my HTML:
<ul style="padding-left:30px;">
<li ng-repeat="query in carousel.currentQuestionObject.choices" style="padding-bottom:5px;" ng-init="carousel.checkboxCollection[query.id] = carousel.currentQuestionObject.init">
<input type="{{carousel.currentQuestionObject.inputType}}" id="{{query.id}}" ng-model="carousel.checkboxCollection[query.id]">
<label for="{{query.id}}" style="font-family:'MetricWeb-Regular';font-size:17px;cursor:pointer"> {{query.question}}</label>
</li>
</ul>
And below is my AngularJS that deals with the radio button answers:
{ inputType: "radio", init:false, question: "Tell us about your needs...",
choices: [
{ question: "Foo1", id: "qs1q1"},
{ question: "Foo2", id: "qs1q2"},
{ question: "Foo3", id: "qs1q3"},
{ question: "Foo4", id: "qs1q4"}
]},
And this is what I'm currently getting:
Please help.
Thank you.

Sharing my solution below. Thank you Simon Pertersen for the guidance! Adding name really did the trick.
HTML:
<ul style="padding-left:30px;">
<li ng-repeat="query in carousel.currentQuestionObject.choices" style="padding-bottom:5px;" ng-init="carousel.checkboxCollection[query.id] = carousel.currentQuestionObject.init">
<input name= "carousel.currentQuestionObject.name" type="{{carousel.currentQuestionObject.inputType}}" id="{{query.id}}" ng-model="carousel.checkboxCollection[query.id]">
<label for="{{query.id}}" style="font-family:'MetricWeb-Regular';font-size:17px;cursor:pointer"> {{query.question}}</label>
</li>
</ul>
AngularJS:
{ inputType: "radio", name: 'qs1needs', init:false, question: "Tell us about your needs...",
choices: [
{ question: "Foo1", id: "qs1q1"},
{ question: "Foo2", id: "qs1q2"},
{ question: "Foo3", id: "qs1q3"},
{ question: "Foo4", id: "qs1q4"}
]},

Related

vue: access a specific array from an object inside an array

I want to show only one of the questions array in a single page, depending on which category the user picks.
faqData = [
{
name: "first-category",
questions: [
{
id: 1,
question: "First question?",
answer: "First Answer"
},
{
id: 2,
question: "Second question?",
answer: "blablablabla"
}
]
},
{
name: "second-category",
questions: [
{
id: 1,
question: "First question?",
answer: "First Answer"
},
{
id: 2,
question: "Second question?",
answer: "blablablabla"
}
]
},
{
name: "third-category",
questions: [
{
id: 1,
question: "First question?",
answer: "First Answer"
}
]
}
];
vue file
<div class="accordion" role="tablist" v-for="eachQuestion in questionList.questions" :key="eachQuestion.id">
<FAQCollapses v-bind:eachQuestion="eachQuestion" />
</div>
//script
data () {
return {
questionList: faqData
}
}
My template code shows a blank space and there's nothing in the console so I'm confused where the mistake is. The problem is I don't know how to specifically get only one category from the faqData array, depending on what category the user clicks. Can someone tell me what is the best practice to achieve my goal? I have read all the similar questions in StackOverflow but it didn't work in my case. Thank you so much.
Best way (and a best practice, I guess), it to implement computed prop with name like, for example selectedFaqQuestion:
computed: {
selectedFaqQuestion () {
return selectedCategory ? this.faqData.find(category => category.name === this.selectedCategory).questions : []
}
}
and use it into v-for:
<div v-for="eachQuestion in selectedFaqQuestion" :key="eachQuestion.id">
<FAQCollapses v-bind:eachQuestion="eachQuestion" />
</div>
Of course, to do so, you need to implement new data prop selectedCategory, where you are going to store selected category, on user's click:
data () {
return {
questionList: faqData,
selectedCategory: null
}
}
So, as you mentioned, you need to handle user click, when going to see any questions based on selected category. To handle its click, you need to use v-on:click. To pass new value of selected category you need to update it: selectedCategory = 'somecategoryname'
'somecategoryname' means something from your faqData prop 'name', for example first-category:
<div> Please, peek FAQ category to show answers:
<span v-on:click="selectedCategory = 'first-category'"> First category </span>
<span v-on:click="selectedCategory = 'second-category'"> Second category </span>
</div>

Concatenate a state with an id | ReactJS

I have multiple checkboxes, when I click on a "Select All/None" checkbox, it works, all the checkboxes are checked, but I want to be able to check each checkbox one by one. My problem is that they all use the same state. So if I click on a checkbox to only check this one, it is checking all the other ones.
So my question is : Is it possible to concatenate an id to a state ?
There are my states :
isAllTablesChecked: false,
isAllReportsChecked: false,
isTableChecked: false,
isReportChecked: false,
tables: [
{id: 1, name: 'Accounts'},
{id: 2, name: 'Asset Types'},
{id: 3, name: 'Assets'},
{id: 4, name: 'Bank Transactions'}
],
report: [
{id: 5, name: 'Aged Payables by Contact'},
{id: 6, name: 'Aged Receivables by Contact'},
{id: 7, name: 'Balance Sheet'},
{id: 8, name: 'Bank Statement'}
]
In a map, below :
const tables = this.state.tables.map(table =>
<div>
<Input
type="checkbox"
name={table.name}
id={this.state.isTableChecked}
checked={this.state.isTableChecked}
onClick={this.checkTables}
/>
<b> {table.name} </b>
</div>
)
const reports = this.state.reports.map(report =>
<div>
<Input
type="checkbox"
name={report.name}
id={this.state.isReportChecked}
checked={this.state.isReportChecked}
onClick={this.checkReports}
/>
<b> {report.name} </b>
</div>
)
For the id line in the <Input> tag, is it possible to do something like :
id={this.state.isTableChecked+tables.id}
Thanks for your help.
I found a solution to my issue.
As I said in my response to Jeremy Harris, I used the checked property inside the JSON data of my state array badly.
Here is the link to the solution, it worked for me :
https://medium.com/#tariqul.islam.rony/multiple-checkbox-handling-by-react-js-84b1d49a46c6
Hope that will help you, I will put this topic as resolved.

AngularJS checkboxes checking from pivot table?

I created the following with the plugin: http://vitalets.github.io/checklist-model/
<section ng-repeat="owner in lord.owners">
<form ng-submit="foobar(owner)" name="update_location_form">
<input type="text" ng-model="owner.name">
<ul>
<li ng-repeat="sheep in sheeps">
<input checklist-model="owner.sheeps" checklist-value="sheep.id" type="checkbox">
<label class="checkbox">{{ sheep.name }}</label>
</li>
</ul>
<button type="submit">Submit</button>
</form>
</section>
All sheeps are shown in the list. And saving to my pivot table (manytomany-relation) also works.
But when I refresh the page, all checks are gone of course. How can I access them?
They're stored in:
{
id: 1,
name: "Obama",
farms: [
{
id: 10,
name: "VirtualFarm",
sheeps: [
{
id: 1,
name: "Foo",
},
{
id: 2,
name: "Bar",
},
{
id: 10,
name: "Cow",
},
{
id: 13,
name: "Hey",
},
]
}
]
}
But I really have now clue how I can check the checkboxes by default that are in the Pivot table.
Someone?
The checklist-model directive automatically checks the appropriate checkboxes based on the value of the checklist-model. You don't have to do anything else, your code looks fine. But ...
First of all, I suspect that owner in lord.owners must be something like owner in x.farms where x is the object that you pasted above.
And this is on the client side and even though you check this boxes, you still need to save them on the server-side. On a refresh, every data not persisted on the server side is lost.

Angular - how to switch between expressions without losing user input

I'm new to Angular so please ELI5 if possible :)
I have a multiple-choice questionnaire with the setup for each question as below:
Question
Choice A
Choice B
Choice C
My controllers look like this:
scope.questionnaire = [
{
questionEN: "Thing?",
choice1EN: "Yes",
choice2EN: "No",
choice3EN: "Maybe",
questionPR: "Treasure?",
choice1PR: "Yarrr",
choice2PR: "Arrrrr",
choice3PR: "Parrrrley"
}
]
My current questionnaire looks like this:
<div ng-bind="questionnaire.questionEN"></div>
<input type="radio" name="{{questionnaire.questionEN}}" ng-model="questionnaire.choice" ng-value="questionnaire.choice1EN">{{questionnaire.choice1EN}}</input> <br />
<input type="radio" name="{{questionnaire.questionEN}}" ng-model="questionnaire.choice" ng-value="questionnaire.choice2EN">{{questionnaire.choice2EN}}</input> <br />
<input type="radio" name="{{questionnaire.questionEN}}" ng-model="questionnaire.choice" ng-value="questionnaire.choice3EN">{{questionnaire.choice3EN}}</input>
What I want to do is that at the start of the questionnaire, there are two buttons that will let the user select between languages.
[English] [Pirate]
So I have two questions, actually:
How do I do the language swapping without losing the user input (for example: they have answered questions 1-5 in [English], and while reading #6, scroll back up and hit the button to swap to [Pirate]. Their selected answers for 1-5 should remain, but all questions+choices have been "translated").
Is there a better way of arranging my controllers?
The answer to this really varies on your particular set of needs. Start with developing a logical model of the problem you are trying to solve.
Things to ask yourself:
Are the questions dynamic (loaded from a database) or static?
How do I need to store the answer? Can I store a choice ID, key, etc. or do I have to use the human readable value?
Does the model that captures the answers have to be different than the model that presents the question?
Do you need to store the language they selected along with the answers?
As you think about it more, other questions will follow.
Anyways, to give you something close to an answer here is a suggestion. If the questions are dynamic, you'll want to create a better structure for defining questions and the choices that are related to them. I'd also give them a key or ID so they can be referred to as concrete concepts. Not only does this help tie the model to database entries, making storing and retrieving easy, it makes it easier for you to handle the language issue.
Here's an example of such a design. You may wish to track the answers separately if your design requires, in my case I just kept it simple and kept the questions and answers in one model.
The question model is an array of objects that look like this:
{
key: 'q1', // unique key for question
text: { // a dictionary of language codes and the text of the question in that language
'en': 'What is the answer the question 1?',
'pr': 'Ahoy 1?'
},
choices: [{
key: 'q1a1', // a unique key for the choice
text: { // a dictionary of language codes and the text of the choice in that language
'en': 'Answer 1',
'pr': 'Arr 1'
}
}, {
key: 'q1a2',
text: {
'en': 'Answer 2',
'pr': 'Arr 2'
}
}],
value: null // the field that stores the user's selected choice
}
There is a helper function to get the language-specific text of the selected choice:
$scope.getAnswer = function(question) {
var answer = $filter('filter')(question.choices, {key: question.value});
if (answer.length == 1) return answer[0].text[$scope.selectedLanguage];
return '(no answer)';
};
The meat of your HTML template that displays the questions looks like this:
<div ng-repeat="question in model">
<label>{{question.text[selectedLanguage]}}</label>
<div>
<label ng-repeat="choice in question.choices">
<input type="radio" name="{{question.key}}" ng-value="choice.key" ng-model="question.value" />{{choice.text[selectedLanguage]}}
</label>
</div>
</div>
Alternative
For the heck of it, here's yet another example of how you might do it. This method is useful if you do not have dynamic question/choice data, but with some effort could still be used for dynamic data. It involves keeping localized UI strings in separate tables, assigning questions and choices unique keys, and then using a translation service to retrieve the correct string. In this example, I use the angular-translate module. I load it with tables of localization strings during .config of my module, specify a default language, and just use the translate filter when displaying questions and choices. This lets me greatly simplify my question model and get rid of some extra work in the views and controller.
My questions simply become:
{
key: 'q1',
choices: [
'q1a1',
'q1a2'
],
value: null
}
I add a watch on the language dropdown to change the current language:
$scope.$watch('selectedLanguage', function(value) {
if (value === null) return;
$translate.use(value);
});
And clean up the template:
<label>{{question.key | translate }}</label>
<div>
<label ng-repeat="choice in question.choices">
<input type="radio" name="{{question.key}}" ng-value="choice" ng-model="question.value" />{{ choice | translate }}
</label>
</div>
You could add a function using ng-click then set your $scope to a new questionnaire.
So you would have something like this:
var english = {
question: "Thing?",
answers: {
choice1: {text: "Yes", val: 1},
choice2: {text: "No", val: 2},
choice3: {text: "Maybe", val: 3}
}
}
var pirate= {
question: "Treasure?",
answers: {
choice1: {text: "Yarrr", val: 1},
choice2: {text: "Arrrrr", val: 2},
choice3: {text: "Parrrrley", val: 3}
}
}
// default
$scope.questionnaire = english;
$scope.choice;
// change language
$scope.changeLanguage = function (lang) {
switch (lang) {
case 0:
$scope.questionnaire = english;
break;
case 1:
$scope.questionnaire = pirate;
break;
}
}
Then for your buttons
<button ng-click="changeLanguage(0)">English</button>
<button ng-click="changeLanguage(1)">Pirate</button>
and finally, I would suggest using ng-repeat in your questionnaire
<div ng-bind="questionnaire.question"></div>
<label ng-repeat="answer in questionnaire.answers" ><input type="radio" name="{{questionnaire.question}}" ng-model="choice" ng-value="answer.val" />{{answer.text}} <br /></label>

AngularJS filter on empty string

I have a simple Angular filter setup between a select and a list. When a user selects an item from the dropdown, the list is updated to show the matching result. The problem is that I have a "Select..." option first in the dropdown with no value, and when that is the selected value, all items are shown. I suppose that makes sense, but I want the opposite. If the selected option has no value, I don't want to show the list. Here are some relevant bits, followed by a link to a full fiddle:
The dropdown:
<select class="world-list" ng-model="selectedWorld" ng-options="world.worldId as world.worldName for world in allWorlds">
<option value="">Select...</option>
</select>
The list:
<ul class="unstyled" id="charList">
<li ng-repeat="char in characters | filter:selectedWorld">
{{char.charName}} - {{char.charRace}} {{char.charClass}}
</li>
</ul>
And here is a link to the full fiddle, which contains my JSON structures that drives all this: http://embed.plnkr.co/6XUmC5efO0Y1BRNLRUig
What I'm trying to do is rather simple, and I'm pretty new to Angular so I'm sure I'm missing something obvious. Checked the Jabbr room, nobody on. :(
Anyway, thanks for any and all help!
One way to accomplish this is to filter by specific properties of the iteration object:
<ul class="unstyled" id="charList">
<li ng-repeat="char in characters | filter:{worldId: selectedWorld}">
{{char.charName}} - {{char.charRace}} {{char.charClass}}
</li>
</ul>
Plunker
I noticed in your code "script.js" you don't seem to be accounting for the blank option.
I did not test this (I probably should prior to posing this answer), but it should work by placing the "blank" option within your script.js.
app.controller('WorldCtrl', function ($scope, $http) {
$scope.allWorlds = [{
worldId: "",
worldName: ""
},
{
worldId: "b8ee0530-744b-463e-9428-23178f6c7bff",
worldName: "World 1"
},
{
worldId: "81211982-5613-4f9c-b704-7b6fa35faf84",
worldName: "World 2"
},
{
worldId: "df41208e-e8d2-46c9-8299-8f37632a51f8",
worldName: "World 3"
}];
$scope.characters = [{
charClass: "Rogue",
charName: "Vaes",
charRace: "Human",
worldId: "b8ee0530-744b-463e-9428-23178f6c7bff"
},
{
charClass: "Warrior",
charName: "Azash",
charRace: "Orc",
worldId: "b8ee0530-744b-463e-9428-23178f6c7bff"
},
{
charClass: "Mage",
charName: "Anele",
charRace: "Ogre",
worldId: "81211982-5613-4f9c-b704-7b6fa35faf84"
}];
});

Resources