Show/Hide button onclick in ng-repeat inside repeat - javascript

How can I access and show/hide the exact button in second repeat?
<div class="row" ng-repeat="person in people">
<div class="row" ng-repeat="ticket in tickets">
<button type="button" ng-if="!ticket.added" ng-click="add(ticket)">+</button>
<button type="button" ng-if="ticket.added" ng-click="remove(ticket)">-</button>
</div>
</div>
For example I have 3 persons and 4 different tickets. When someone click on button I want to add clicked ticket for that person.
Now when I click on add button, it's adding clicked ticket for all persons :(
Thanks in advance!

I'm not sure (your question is not too clear) but, maybe you can pass the person to your functions too?
Example:
$scope.people = [{
name: 'Jhon Snow',
tickets: [{
name: 'ticket1',
added: false
}, {
name: 'ticket2',
added: false
}]
}, {
name: 'Peter Parker',
tickets: [{
name: 'ticket3',
added: false
}, {
name: 'ticket4',
added: false
}]
}];
$scope.add = function (ticket) {
ticket.added = true;
}
$scope.remove = function (ticket) {
ticket.added = false;
}
And the html:
<div class="row" ng-repeat="person in people">
{{ person.name}}
<div class="row" ng-repeat="ticket in person.tickets">
- {{ ticket.name }}
<button type="button" ng-if="!ticket.added" ng-click="add(ticket)">+</button>
<button type="button" ng-if="ticket.added" ng-click="remove(ticket)">-</button>
</div>
</div>
You can check a working example here

Related

How can I dynamically move child div between parent divs using Knockout?

In my sample, I have three parent divs (colored red) ... First, Second and Third.
Initially I want to put my child div (colored yellow) in the "Second" div.
After this, I want to move the child div between parent divs just by changing columnID.
Here's my test code that does not work...
var dataColumns = [{
id: 1,
text: "First"
},
{
id: 2,
text: "Second"
},
{
id: 3,
text: "Third"
}
]
var viewModel = {
data: ko.observableArray([]),
columns: ko.observableArray([]),
};
dataColumns.forEach(function(c) {
let column = {
id: c.id,
text: c.text,
items: ko.computed(function() {
return ko.utils.arrayFilter(viewModel.data(), function(d) {
return d.columnID() === c.id;
});
}, this)
};
viewModel.columns.push(column);
});
ko.applyBindings(viewModel);
let item = {
columnID: ko.observable(2),
caption: "I am the moving item"
};
viewModel.data.push(item);
function MoveTo(index) {
item.columnID(index);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div data-bind="template: { name: 'columnTemplate', foreach: columns, as: 'column' }"></div>
<script type="text/html" id="columnTemplate">
<div style="background-color: red;">
<div data-bind="text: text"></div>
<div data-bind="template: { name: 'itemTemplate', foreach: column.items, as: 'item' }"></div>
</div>
</script>
<script type="text/html" id="itemTemplate">
<div style="background-color: yellow;">
<div data-bind="text: caption"></div>
</div>
</script>
<button onclick="MoveTo(1)">Move to column 1</button>
<button onclick="MoveTo(2)">Move to column 2</button>
<button onclick="MoveTo(3)">Move to column 3</button>
Fiddle: https://jsfiddle.net/MojoDK/at8grkwe/3/
Is my goal impossible to do with Knockuot?
My reallife project is a kanban system, where the id of the task specify which kanban column the task should be in - and then just by changeing then tasks columnID, the task should be moved to another kanban column.
UPDATE:
I updated snippet and Fiddle to correct the error HeyJude pointed out - but it still doesn't move between columns when clicking the buttons.
It's only a small mistake you've got there.
Change this:
viewModel.columns.push(c);
... into this:
viewModel.columns.push(column);

Radio button cannot be checked when using with VueJS

I created a quiz by using VueJS. However, there is something that blocks me from clicking on radio buttons. It will check another radio button rather than the one that I want.
HTML code
<div id="app">
<h1>{{ quiz.title }}</h1>
<div v-for="(question, index) in quiz.questions" class="question-content">
<div v-show="index === questionIndex" class="question-box">
<h4>{{ question.text }}</h4>
<ol>
<li v-for="response in question.responses">
<label>
<input type="radio"
v-bind:value="response.correct"
v-bind:name="index"
v-model="userResponses[index]"> {{response.text}}
</label>
</li>
</ol>
<button v-if="questionIndex > 0" v-on:click="prev">
Prev
</button>
<button v-on:click="next">
Next
</button>
</div>
</div>
<div v-show="questionIndex === quiz.questions.length">
<h2>
Quiz finished
</h2>
<p>
Total score: {{ score() }} / {{ quiz.questions.length }}
</p>
<button v-on:click="start">
Restart
</button>
</div>
</div>
VueJS code
// A question has one or more answer, and one or more is valid.
var quiz = {
title: 'Quiz',
questions: [
{
text: "1. Which of the following is a category or element of the balance sheet?",
responses: [
{text: 'Expenses'},
{text: 'Gains'},
{text: 'Liabilities', correct: true},
{text: 'Losses'},
]
}, {
text: "2. Which of the following is an asset account?",
responses: [
{text: 'Accounts Payable'},
{text: 'Prepaid Insurance', correct: true},
{text: 'Unearned Revenue'}
]
}
]
};
new Vue({
el: '#app',
data: {
quiz: quiz,
// Store current question index
questionIndex: 0,
// An array initialized with "false" values for each question
// It means: "did the user answered correctly to the question n?" "no".
userResponses: Array(quiz.questions.length).fill(false)
},
// The view will trigger these methods on click
methods: {
// Go to next question
next: function() {
this.questionIndex++;
},
// Go to previous question
prev: function() {
this.questionIndex--;
},
// Return "true" count in userResponses
score: function() {
return this.userResponses.filter(function(val) { return val }).length;
},
// Restart quiz
start: function() {
this.questionIndex = 0;
}
}
});
You can check the live code at : https://jsfiddle.net/dalenguyen/z4rj62c6/1/
Use Nested index for name attribute.
HTML
<div id="app">
<h1>{{ quiz.title }}</h1>
<div v-for="(question, index) in quiz.questions" class="question-content">
<div v-show="index === questionIndex" class="question-box">
<h4>{{ question.text }}</h4>
<ol>
<li v-for="(response, child_index) in question.responses">
<label>
<input type="radio" v-bind:value="response.text" v-bind:name="response.text" v-model="userResponses[index]"> {{response.text}}
</label>
</li>
</ol>
<button v-if="questionIndex > 0" v-on:click="prev">
Prev
</button>
<button v-on:click="next">
Next
</button>
</div>
</div>
<div v-show="questionIndex === quiz.questions.length">
<h2>
Quiz finished
</h2>
<p>
Total score: {{ score() }} / {{ quiz.questions.length }}
</p>
<button v-on:click="start">
Restart
</button>
</div>
</div>
JS: Calculate Correct Ans
score: function() {
correctCount = 0;
that = this;
this.quiz.questions.filter(function(val, i) {
val.userAnswerCorrect = false;
val.userAnswer = that.userResponses[i];
val.responses.filter(function(ans, j) {
if (ans.correct == true && val.userAnswer == ans.text) {
correctCount++;
}
})
});
return correctCount;
}
Demo: https://jsfiddle.net/sumitridhal/esshqr25/
Just doing the following change will make it work:
v-bind:value="response.text"
response.correct was making all other values undefined, so the radio was getting confused which is the correct value!
I hope that helps!

How to add a link in javascript

I have the following Javascript that I am using to make a sort of flowchart where the user clicks through a set of questions. For certain responses i want to link to an external site where more info can be found. How do I add these links?
HTML
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<div class="wrapper">
<div class="container">
<div class="row">
<div class="col-xs-12 text-right">
<button class="btn btn-default btn-corner" type="submit" data-bind="click: startOver, visible: queryData().id > 0">Start over</button>
</div>
</div>
</div>
<div class="container main">
<div class="row">
<div class="c12 text-center">
<h1 data-bind="text: queryData().text"></h1>
<h3 data-bind="text: queryData().subhead"></h3>
<div class="option-group" data-bind="foreach: queryData().answers">
<button class="btn btn-default btn-lg" type="submit" data-bind="click: $parent.goToTarget, text: text"></button>
</div>
<button class="btn btn-default" type="submit" data-bind="click: stepBack, visible: navHistory().length > 1">Previous Step</button>
</div>
</div>
</div>
<div class="push"></div>
</div>
<script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-3.3.0.js"></script>
<script src="app.js?v=0.4.0"></script>
<script>
</script>
</body>
</html>
The Javascript is as follows:
JS
var queries = [{
id: 0,
text: "Where to start?",
answers: [{
text: "Let's Begin!",
target: 1
}]
}, {
id: 1,
text: "Which genre do you want to start in?",
answers: [{
text: "Fantasy",
target: 100
}, {
text: "SciFi",
target: 2
}, {
text: "Neither",
target: 59
}]
}, {
id: 2,
text: "It's huge but it's worth it. The Cryptonomicon by Neal Stephenson",
answers: [{
text: "Amazon.co.uk",
target: "_blank"
}, {
text: "Amazon.com"
}]
}];
function QueryViewModel() {
var self = this;
self.querySet = ko.observable();
self.currentStep = ko.observable();
self.queryData = ko.observable();
self.sfw = ko.observable();
self.navHistory = ko.observableArray();
// Operations
self.goToTarget = function(obj) {
self.navHistory.push(self.currentStep());
self.currentStep(obj.target);
self.queryData(self.querySet()[obj.target]);
}
self.startOver = function() {
self.navHistory.removeAll();
self.goToTarget({target: 0});
}
self.stepBack = function() {
var lastStep = self.navHistory().length > 1 ? self.navHistory.pop() : 0;
self.currentStep(lastStep);
self.queryData(self.querySet()[lastStep]);
}
var paramsString = document.location.hash.substring(1);
var params = new Array();
if (paramsString) {
var paramValues = paramsString.split("&");
for (var i = 0; i < paramValues.length; i++) {
var paramValue = paramValues[i].split("=");
params[paramValue[0]] = paramValue[1];
}
}
params ? paramTarget = params['target'] : params = [];
self.sfw() ? self.querySet(queriesSFW) : self.querySet(queries);
if (paramTarget) {
self.navHistory.push(0);
self.currentStep(0);
self.goToTarget({target: paramTarget})
} else {
self.goToTarget({target: 0});
}
}
ko.applyBindings(new QueryViewModel());
In html you can do something like this:
<button type="button" onclick="window.open('https://google.com/', '_self')">Button</button>
You don't have to use a button, different elements can use onclick like text or images. This can also call js functions, just put the function name where "window.open..." is.
Of course the standard way to do it is
<a href='https://www.google.com/'>Link</a>
You can practice using js here: http://www.w3schools.com/js/tryit.asp?filename=tryjs_intro_inner_html
and learn more about it here: http://www.w3schools.com/js/js_intro.asp
I am not sure why you would show us the JSON for open a link to another page. Unless I misunderstood. This kind of basic information can be found by a quick Google search.
Add your link in the object like:
text: "Fantasy",
link: "http://www.stackoverflow.com",
target: 2
Now when you need to go to that link, use this function:
var link = obj.link;
window.open(link, "_blank");

Knockout.js {{each}} not listing items in javascript template

I've created a simple app that should iist each item from a model in a list, created using a javascrit template.
Fiddle
Html:
<div id="tagsList" class="box">
<div class="box-head">
<h2 class="left">Tags</h2>
</div>
<div class="box-content">
<input type="text" placeholder="Add New Tag" />
<button>+ Add</button>
<div data-bind="template: 'tagsTempl'"></div>
</div>
</div>
<script id="tagsTempl" type="text/html">
<ul>
{{each tags}}
<li class="tagItem">
<span>${Name}</span>
<div>
Edit
Delete
</div>
</li>
{{/each}}
</ul>
</script>
Javascript:
$(function () {
//$("#tagDialog").hide();
var data = [
{ Id: 1, Name: "Ball Handling" },
{ Id: 2, Name: "Passing" },
{ Id: 3, Name: "Shooting" },
{ Id: 4, Name: "Rebounding" },
{ Id: 5, Name: "Transition" },
{ Id: 6, Name: "Defense" },
{ Id: 7, Name: "Team Offense" },
{ Id: 8, Name: "Team Defense" }
];
var viewModel = {
tags: ko.observableArray(data),
tagToAdd: ko.observable(""),
addTag: function() {
this.tags.push({ Name: this.tagToAdd() });
}
}
ko.applyBindings(viewModel)
});
Output of list:
{{each tags}}
${Name}
Edit Delete
{{/each}}
The scripts file is accessible through viewing source. I'm not sure where my error is. Any help?
I updated your fiddle. Now it is working like you want it to: The list of tags is being rendered using the knockout standard method as described in the docs.
HTML
<ul data-bind="template: {name: 'tagsTempl', foreach: tags}"></ul>
Template
<script id="tagsTempl" type="text/html">
<li class="tagItem">
<span data-bind="text: Name"></span>
<div>
Edit
Delete
</div>
</li>
</script>
Also I connected the viewmodel to the view.
For example:
<button data-bind="click: addTag">+ Add</button>
You simply forgot most of it. I suggest you follow the interactive tutorials on how to do this.

Pass array into ng-click

http://jsfiddle.net/u0jzkye1/
<div ng-app ng-controller="MyCtrl">
<ul>
<li ng-repeat="item in items">{{item.name}}</li>
</ul>
<button type="submit" ng-click="send()">
Send
</button>
</div>
When the button is not within ng-repeat, how can I pass my item's id into ng-click function?
Well items is already on $scope as you're using it in your ng-repeat. So you should simply be able to ng-click="send(items)"
var items = [{
id: 1,
name: "one"
}, {
id: 2,
name: "two"
}];
function MyCtrl($scope) {
$scope.items = items;
$scope.send = function() {
//get items' id
$scope.items.forEach(function(item){
alert(item.id);
}, this);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app ng-controller="MyCtrl">
<ul>
<li ng-repeat="item in items">{{item.name}}</li>
</ul>
<button type="submit" ng-click="send()">
Send
</button>
</div>

Categories