demo:
https://jsfiddle.net/8hh0p0ej/
In this demo,there is a selected attribute in items,which control the item selected or not and "allSelected".
Question:
When I use it in my project,the content of items will be gotten form mysql,there is no selected field,the status of one item doesn't need to be recorded,so I don't want to add this field,how to accomplish "Allselected" in this situation?
You can add a selected member to the data after it is fetched.
var vm = new Vue({
el: "#app",
data: {
items: []
},
methods: {
fillIn: function(index, n) {
this.items[index].num = n;
}
},
computed: {
nums: function() {
return [1, 2, 3, 4, 5];
},
allSelected: {
get: function() {
for (var i = 0, length = this.items.length; i < length; i++) {
if (this.items[i].selected === false) {
return false;
}
}
return true;
},
set: function(val) {
for (var i = 0, length = this.items.length; i < length; i++) {
this.items[i].selected = val;
}
}
},
sum: function() {
var totalAmount = 0;
for (var i = 0, length = this.items.length; i < length; i++) {
var item = this.items[i];
if (item.selected === true) {
totalAmount += item.price * item.num;
}
}
return totalAmount;
}
}
});
// Data as it might come from mysql
mysqlData = [{
message: 'Apple',
num: 1,
price: 5
}, {
message: 'Peach',
num: 1,
price: 10
}, {
message: 'Orange',
num: 1,
price: 15
}, {
message: 'Pear',
num: 1,
price: 20
}];
// Modify the data when we put it in the vm
vm.$set('items', mysqlData.map((item) => {
item.selected = false;
return item;
}));
<link href="//cdnjs.cloudflare.com/ajax/libs/tether/1.3.7/css/tether.min.css" rel="stylesheet" />
<script src="//cdnjs.cloudflare.com/ajax/libs/tether/1.3.7/js/tether.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="//cdn.bootcss.com/bootstrap/4.0.0-alpha.3/css/bootstrap.min.css" rel="stylesheet" />
<script src="//cdn.bootcss.com/bootstrap/4.0.0-alpha.3/js/bootstrap.min.js"></script>
<script src="//cdn.bootcss.com/vue/1.0.26/vue.min.js"></script>
<div class="container">
<div class="card">
<h3 class="card-header">Cart</h3>
<div class="card-block">
<div id="app">
<div class="row">
<div class="col-xs-3">
<label class="c-input c-checkbox">
<input type="checkbox" v-model="allSelected">Select All
<span class="c-indicator"></span>
</label>
</div>
<div class="col-xs-2">
Goods
</div>
<div class="col-xs-5">
Number
</div>
<div class="col-xs-2">
Money
</div>
</div>
<form>
<div class="row" v-for="(index, item) in items">
<div class="col-xs-3">
<label class="c-input c-checkbox">
<input type="checkbox" v-model="item.selected">
<span class="c-indicator"></span>
</label>
</div>
<div class="col-xs-2">
{{ item.message }}
</div>
<div class="col-xs-5">
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-text="item.num">
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li v-for="n in nums">
<a class="dropdown-item" #click="fillIn(index, n)">{{n}}个</a>
</li>
</ul>
</div>
</div>
<div class="col-xs-2">
{{ item.price * item.num }}
</div>
</div>
<div class="row">
<div class="col-xs-3">
Sum
</div>
<div class="col-xs-2">
</div>
<div class="col-xs-5">
</div>
<div class="col-xs-2">
{{ sum }}
</div>
</div>
<button type="submit" class="btn btn-primary" :disabled="sum === 0">Submit</button>
</form>
</div>
</div>
</div>
</div>
You could keep a separate object with the id of the object as a key and a Boolean value, that represents if the item is selected or not.
The items data would only have, message, num and price
While the selected data would have itemid and selected
Related
I want to show different json after click into any radio button. 'Option 1' will get option1.json etc.
Is is possible to do it without page refresh?
$('#my_radio_box').change(function(){
selected_value = $("input[name='my_options']:checked").val();
if (selected_value == 'option 2'){
const products =
[
{id: 11,title: '2Macbook Pro', price: 2500.00, qty: 1, image: 'http://lorempixel.com/150/150/'},
{id: 12,title: '2Asus ROG Gaming',price: 1000.00, qty: 1,image: 'http://lorempixel.com/150/150/'},
{id: 13,title: '2Amazon Kindle',price: 150.00,qty: 1,image: 'http://lorempixel.com/150/150/'},
{id: 14,title: '2Another Product',price: 10, qty: 1, image: 'http://lorempixel.com/150/150/'},
];
}
});
$(document).ready(function(){
$('#my_radio_box').change(function(){
selected_value = $("input[name='my_options']:checked").val();
if (selected_value == 'option 2'){
// const products = ...
}
});
});
const products =
[
{id: 1,title: 'Macbook Pro', price: 2500.00, qty: 1, image: 'http://lorempixel.com/150/150/'},
{id: 2,title: 'Asus ROG Gaming',price: 1000.00, qty: 1,image: 'http://lorempixel.com/150/150/'},
{id: 3,title: 'Amazon Kindle',price: 150.00,qty: 1,image: 'http://lorempixel.com/150/150/'},
{id: 4,title: 'Another Product',price: 10, qty: 1, image: 'http://lorempixel.com/150/150/'},
];
function formatNumber(n, c, d, t){
var c = isNaN(c = Math.abs(c)) ? 2 : c,
d = d === undefined ? '.' : d,
t = t === undefined ? ',' : t,
s = n < 0 ? '-' : '',
i = String(parseInt(n = Math.abs(Number(n) || 0).toFixed(c))),
j = (j = i.length) > 3 ? j % 3 : 0;
return s + (j ? i.substr(0, j) + t : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : '');
};
// Allow the formatNumber function to be used as a filter
Vue.filter('formatCurrency', function (value) {
return formatNumber(value, 2, '.', ',');
});
// The shopping cart component
Vue.component('shopping-cart', {
props: ['items'],
computed: {
Total() {
let total = 0;
this.items.forEach(item => {
total += (item.price * item.qty);
});
return total;
}
},
methods: {
// Remove item by its index
removeItem(index) {
this.items.splice(index, 1)
}
}
})
const vm = new Vue({
el: '#app',
data: {
cartItems: [],
items : products
},
methods: {
// Add Items to cart
addToCart(itemToAdd) {
let found = false;
// Add the item or increase qty
let itemInCart = this.cartItems.filter(item => item.id===itemToAdd.id);
let isItemInCart = itemInCart.length > 0;
if (isItemInCart === false) {
this.cartItems.push(Vue.util.extend({}, itemToAdd));
} else {
itemInCart[0].qty += itemToAdd.qty;
}
itemToAdd.qty = 1;
}
}
})
.container{
padding:20px;
max-width:600px;
}
.input-qty {
width: 60px;
float: right
}
.table-cart > tr > td {
vertical-align: middle !important;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
<div id="app" class="container">
<div class="text-right"><button class="btn btn-primary" data-toggle="modal" data-target="#cartModal">Cart ({{cartItems.length}})</button></div>
<form id="my_radio_box">
<input type="radio" name="my_options" value="option 1" checked="checked" /> Option 1
<input type="radio" name="my_options" value="option 2" /> Option 2
<input type="radio" name="my_options" value="option 3" /> Option 3
</form>
<!-- Modal -->
<div class="modal fade" id="cartModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">Cart</h4>
</div>
<div class="modal-body">
<shopping-cart inline-template :items="cartItems">
<div>
<table class="table table-cart">
<tr v-for="(item, index) in items">
<td>{{item.title}}</td>
<td style="width:120px">QTY:
<input v-model="item.qty" class="form-control input-qty" type="number">
</td>
<td class="text-right">${{item.price | formatCurrency}}</td>
<td>
<button #click="removeItem(index)"><span class="glyphicon glyphicon-trash"></span></button>
</td>
</tr>
<tr v-show="items.length === 0">
<td colspan="4" class="text-center">Cart is empty</td>
</tr>
<tr v-show="items.length > 0">
<td></td>
<td class="text-right">Cart Total</td>
<td class="text-right">${{Total | formatCurrency}}</td>
<td></td>
</tr>
</table>
</div>
<!-- /.container -->
</shopping-cart>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-xs-3 text-center" v-for="item in items">
<img class="img-responsive" :src="item.image" alt="">
<h5>{{ item.title }}</h5>
<h6>${{ item.price | formatCurrency }}</h6>
<p class="text-center"><input v-model="item.qty" type="number" class="form-control" placeholder="Qty" min="1"/></p>
<button #click="addToCart(item)" class="btn btn-sm btn-primary">Add to Cart</button>
</p>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="app.js"></script>
I'm a new mvc developper, I make a list in my controller, my view show this list and for each row i have a button for a modal view.I want to pass the data of the ViewBag in my list according for each row in my modal.
This is my modal html:
<div class="modal" id="addBadgetoStudentModal-#item.ID" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg animated bounceInDown">
<div class="modal-content">
#using (Html.BeginForm("AddBadgeToStudent", "Badges", new { ID = item.ID }, FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="modal-header">
<h4 class="modal-title">Badges</h4>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
</div>
<div class="modal-body">
<div class="form-group">
<div class="">
<div class="row">
#if (ViewBag.Badges != null)
{
for (var i = 0; i < ViewBag.Badges.Count; i++)
{
<div class="col-lg-3 col-sm-6 col-md-4">
<div class="team-member ">
<div class="row margin-0">
<div class="team-info" style="text-align:center; border: 1.2pt solid #1874BF;">
<img src="#ViewBag.Badges[i].ImageURL" style="width:80%;" class="img-fluid" />
</div>
<div class="team-info" style="text-align:center; width:100%;">
#ViewBag.Badges[i].Label
<br />
<input id="Badge_#ViewBag.Badges[i].ID" class="checkBoxBadgeClass" type="checkbox" />
</div>
</div>
</div>
</div>
}
}
</div>
</div>
</div>
</div>
<div class="modal-footer">
<i class="fa fa-plus-circle"></i> #Resource.Add
</div>
}
</div>
</div>
</div>
<a class="fa fa-pencil-alt" data-toggle="modal" href="#addBadgetoStudentModal-#item.ID" onclick="btnModal()"></a>
This is my List Html View:
#foreach (var item in Model)
{
<tr id="#item.ID">
<td style="text-align:center; width:5%;">
#Html.DisplayFor(modelItem => item.ID)
</td>
<td style="text-align: center; width:25%;">
#item.FullName
</td>
<td style="width:450px;">
#for (var i = 0; i < item.BadgesAssigned.Count; i++)
{
<img src="#item.BadgesAssigned[i].ImageUrl" width="50" title="#item.BadgesAssigned[i].Name" style="float:left;" />
}
<input type="hidden" id="studentBadges_#item.ID" value="#String.Join(",", item.BadgesAssigned.Select(x => x.ID.ToString()))"/>
</td>
}
and this my controller to get my student list and in another table get the badge assigned to a student, so in the list view the student can have 20 badges/25:
public ActionResult BadgeManagement(int? CohortId, int? id)
{
ViewBag.CohortId = db.Cohorts.Select(p => new SelectListItem
{
Text = p.Name,
Value = p.ID.ToString()
});
if (CohortId != null ? CohortId > 0 : false)
{
var cs = db.CohortSubscriptions.Where(student => student.CohortId == CohortId).Include(c => c.Cohorts).Include(c => c.Registrations);
List<BadgesByStudentViewModel> badgesByStudentList = new List<BadgesByStudentViewModel>();
foreach (var student in cs) {
badgesByStudentList.Add(new BadgesByStudentViewModel
{
ID = student.ID,
FullName = student.Registrations.FullName,
BadgesAssigned = db.Enrolled_Students_Badges.Where(x => x.CohortSubscriptionId == student.ID).Select(x => new BadgesAssigned
{
ID = x.ID,
Name = x.Label,
ImageUrl = x.ImageURL
}).ToList()
});
}
ViewBag.Badges = db.Badges.ToList();
return View(badgesByStudentList.ToList());
}
return View(new List<BadgesByStudentViewModel>());
}
I found my solution
This is my html:
<tbody>
#foreach (var item in Model)
{
<tr id="#item.ID">
<td style="text-align:center; width:5%;">
#Html.DisplayFor(modelItem => item.ID)
</td>
<td style="text-align: center; width:25%;">
#item.FullName
</td>
<td style="width:450px;">
#for (var i = 0; i < item.BadgesAssigned.Count; i++)
{
<img src="#item.BadgesAssigned[i].ImageUrl" width="50" title="#item.BadgesAssigned[i].Name" style="float:left;" />
}
</td>
<td style="text-align:center; width:5%;">
<button style="border:none;background: transparent;" data-studentid="#item.ID" data-studentname="#item.FullName" data-badges="#String.Join(",", item.BadgesAssigned.Select(x => x.ID.ToString()))" data-toggle="modal" data-target="#addBadgetoStudentModal" class="modalLink"><i class="fa fa-pencil-alt"></i></button>
</td>
</tr>
}
</tbody>
</table>
<div class="modal" id="addBadgetoStudentModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg animated bounceInDown">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Badges</h4>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
</div>
<div class="modal-body">
<div class="form-group">
<div class="">
<u>#Resource.AddBadgeToStudent:</u>
<br />
<br />
<div class="row">
#if (ViewBag.Badges != null)
{
for (var i = 0; i < ViewBag.Badges.Count; i++)
{
<div class="col-lg-3 col-sm-6 col-md-4">
<div class="team-member ">
<div class="row margin-0">
<div class="team-info" style="text-align:center; border: 1.2pt solid #1874BF;">
<img src="#ViewBag.Badges[i].ImageURL" style="width:80%;" class="img-fluid" />
</div>
<div class="team-info" style="text-align:center; width:100%;">
#ViewBag.Badges[i].Label
<br />
<input id="Badge_#ViewBag.Badges[i].ID" data-badgeid="#ViewBag.Badges[i].ID" data-label="#ViewBag.Badges[i].Label" class="checkBoxBadgeClass" type="checkbox" />
</div>
</div>
</div>
</div>
}
}
</div>
</div>
</div>
</div>
<div class="modal-footer">
<i class="fa fa-plus-circle"></i> #Resource.Edit
</div>
</div>
</div>
</div>
and this is my jquery:
currentStudentId = null;
currentAssignedBadge = [];
$('#BadgeAssignmentTable').dataTable({
responsive: true,
aLengthMenu: [
[10, 25, 50, 100, -1],
[10, 25, 50, 100, "All"]
]
});
$(".modalLink").on("click", function () {
var $pencil = $(this);
var studentId = $pencil.data('studentid');
var badges = $pencil.data('badges');
var studentName = $pencil.data("studentname");
PrepareBadgesModal(studentId, badges.split(","), studentName);
});
PrepareBadgesModal = function (studentId, assignedBadges, studentName) {
currentStudentId = studentId;
console.log(assignedBadges);
currentAssignedBadge = [];
$.each(assignedBadges, function (k, v) { return currentAssignedBadge.push(parseInt(v, 10)); });
$.each(assignedBadges, function (k, v) {
var $badge = $("#Badge_" + v);
$badge.prop("checked", true);
var label = $badge.data("label");
$badge.on("click", function (event) {
var res = ConfirmRemoveBadge($(this), label, studentName);
event.stopPropagation();
});
});
}
ConfirmRemoveBadge = function ($badge, label, studentName) {
var txt = "ATTENTION\r\rÊtes-vous certain de vouloir retirer le badge \"" + label + "\" à " + studentName + "?";
var r = confirm(txt);
if (r == true) {
$badge.prop("checked", false);
$badge.unbind("click");
} else {
$badge.prop("checked", true);
}
}
$("#AssignBadges").click(function () {
ModifyBadgesAction();
});
ModifyBadgesAction = function (badgeList) {
var selBadgeLst = $('input[id^=Badge_]:checked').map(function (k, v) { return parseInt($(v).data('badgeid'), 10); });
//TODO: Close the modal
var removedLst = $.grep(currentAssignedBadge, function (v, k) {
return $.grep(selBadgeLst, function (vv, kk) {
return v == vv;
}).length == 0;
});
var AddedList = $.grep(selBadgeLst, function (v, k) {
return $.grep(currentAssignedBadge, function (vv, kk) {
return v == vv;
}).length == 0;
});
var jsonData = JSON.stringify({ studentId : currentStudentId, AddedList: AddedList, removedLst: removedLst });
$.ajax({
contentType: 'application/json; charset=utf-8',
dataType: 'json',
type: 'POST',
url: '/Badges/ModifyBadgesAction',
data: jsonData,
success: function (data, textStatus, jqXHR) {
//console.log(data, textStatus, jqXHR);
if (data.code == 0) {
ApplyBadgeActionSuccess(data);
}
else {
ApplyBadgeActionError(data);
}
},
error: function (jqXHR, textStatus, errorThrown) {
ApplyBadgeActionError({ code: jqXHR.status, message: "Technical Error", data: [{ jqXHR: jqXHR, error: errorThrown }] });
}
});
};
ApplyBadgeActionSuccess = function (data) {
alert(data.message);
window.location.reload(true);
}
ApplyBadgeActionError = function (data) {
alert(data.message);
}
Good Day!
I'm working on my project right now and I need to dynamically add form when button click. I have a nested accordion and inside the accordion is ng-select. To make it clear this is my code
<div class="box box-default" *ngFor="let form of forms; let form_array_index = index">
<div class="box-header with-border text-center">
<h3 class="box-title">
<div class="row">
<div class="col-md-4">
<select2 id="segment" name="segment"
[data]="add_segment"
[width]="293"
[value]="segment_value"
(valueChanged)="changedSegment($event, form_array_index)"
required>
</select2>
</div>
</div>
</h3>
<div class="box-tools pull-right">
</div>
</div>
<div class="box-body">
<div class="row">
<div class="col-md-2">
<label for="category">Values:</label>
<select2 id="category" name="category"
[options]="options"
[data]="add_category"
[width]="293"
[value]="category_value"
(valueChanged)="changedCategory($event, form_array_index)"
required>
</select2>
</div>
</div>
<div class="box-header with-border text-center" *ngIf="cat_value">
<div class="panel panel-default">
<div class="panel-heading">
<h5 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion1" href="#{{ category_current[form_array_index] }}">{{collection_category[form_array_index].category}}
</a>
</h5>
</div>
<div id="{{ category_current[form_array_index] }}" class="panel-collapse collapse">
<div class="panel-body">
<div class="panel-body">
<button class="btn btn-success btn-xs pull-left" (click)="addQuestions()">Add Question</button>
<div class="row" >
<select2 *ngIf="query" id="question" name="question"
[data]="add_question"
[width]="293"
[value]="question_value"
(valueChanged)="changedQuestion($event)"
required>
</select2>
</div>
<button class="btn btn-success btn-xs pull-left" (click)="addSubCat()">Add Sub Category</button>
<div class="row" >
<select2 *ngIf="subcat" id="subcategory" name="subcategory"
[options]="options"
[data]="add_subcategory"
[width]="293"
[value]="subcategory_value"
(valueChanged)="changedSubcategory($event, form_array_index)"
required>
</select2>
</div>
<div class="panel-group" id="accordion21" *ngIf="subcat">
<ul class="list-group">
<li class="list-group-item" >
<div class="panel">
<a data-toggle="collapse" data-parent="#accordion21" href="#{{ subcategory_current }}" >
<strong>{{ get_subcategory }} </strong>
</a>
<div id="{{subcategory_current}}" class="panel-collapse collapse">
<div class="panel-body">
<label for="question">Question:</label>
<select2 id="question" name="question"
[data]="add_question"
[width]="293"
[value]="question_value"
(valueChanged)="changedQuestion($event)"
required>
</select2> <br>
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div></div>
</div>
<div class="box-tools pull-right">
</div>
</div>
</div>
This means in SEGMENT it can have multiple CATEGORY and inside category it can have a question or they they Choose SUB CATEGORY and they have to choose a question
This is my component.ts
public collection_category = [];
public collection_subcategory = [];
addSegment(){
this._q_service.addSegment().
subscribe(
data => {
this.add_segment = Array.from(data);
let id = 0;
let text = 'Select Segment';
this.add_segment.unshift({id,text});
// this.segment_value = [];
this.segment_current = this.segment_value;
},
err => console.error(err)
);
}
changedSegment(data: any, form_array_index: any) {
this.segment_current = data.value;
if(this.segment_current.length > 0){
for (let i = 0; i < this.add_segment.length; ++i) {
if (this.add_segment[i].id == this.category_current) {
this.collection_category[form_array_index].segment = this.add_segment[i].text;
}
}
}
console.log('segment', this.collection_category);
}
addCategory(){
this._q_service.addCategory().
subscribe(
data => {
this.add_category = Array.from(data);
this.category_value = [];
this.options = {
multiple: true
}
let id = 0;
let text = 'Select Category';
this.add_category.unshift({id,text});
this.category_value = [];
// this.category_current.push(this.category_value);
// console.log(this.category_current);
},
err => console.error(err)
);
}
changedCategory(data: any, form_array_index: any ) {
this.category_current = data.value;
if(this.category_current.length > 0){
let len = this.add_category.length;
for (let i = 0; i < len; ++i) {
if (this.add_category[i].id == this.category_current) {
this.get_category = this.add_category[i].text;
this.collection_category[form_array_index].category = this.add_category[i].text;
}
}
this.cat_value = true;
}
console.log(this.collection_category);
this.addSubCategory();
this.addQuestion();
}
addSubCategory(){
this._q_service.addSubCategory().
subscribe(
data => {
this.add_subcategory = Array.from(data);
this.subcategory_value = [];
this.options = {
multiple: true
}
let id = 0;
let text = 'Select Sub Category';
this.add_subcategory.unshift({id,text});
this.subcategory_value = [];
this.subcategory_current = this.subcategory_value;
},
err => console.error(err)
);
}
changedSubcategory( data: any, form_array_index: any ) {
this.subcategory_current = data.value;
if(this.subcategory_current.length > 0){
let len = this.add_subcategory.length;
for (let i = 0; i < len; ++i) {
if (this.add_subcategory[i].id == this.subcategory_current) {
this.get_subcategory = this.add_subcategory[i].text;
this.collection_category[form_array_index].subcategory = this.add_subcategory[i].text;
// this.collection_subcategory[form_array_index].subcategory_collection = [];
}
}
this.sub_value = true;
}
}
addQuestion(){
this._q_service.questionList().
subscribe(
data => {
this.add_question = Array.from(data);
this.question_value = [];
let id = 0;
let text = 'Select Question';
this.add_question.unshift({id,text});
this.subcategory_value = ['0'];
this.question_current = this.question_value;
},
err => console.error(err)
);
}
changedQuestion(data: any) {
this.question_current = data.value;
if(this.question_current != 0){
let len = this.add_question.length;
for (let i = 0; i < len; ++i) {
if (this.add_question[i].id == this.question_current) {
this.get_question = this.add_question[i].text;
}
}
}
}
addFormRow(){
let new_form ={
id: '',
segment: '',
category: '',
subcategory: '',
question: ''
};
// this.category_current.push(0);
let segment_categories = {
segment: '',
category: '',
subcategory: '',
question: ''
};
//this.category_current[form_array_index].category
this.collection_category.push(segment_categories);
this.forms.push(new_form);
}
*And every time the user hit the Add Form button it dynamically add form *
But it gives me an error every time I add form the first accordion is not working on the second form but the first form is working well
I have a subscription feature which is open through checking a radio box. When open inside this section I have 2 radio buttons for subscribe the period weekly or monthly and below an item. When I pressing save the state of this period have to be saved for one item I have from the server. You can check the screenshot to see the view. Anyway, there is no save because the array result empty and that item is not in that array. My problem is I see the item below but somehow I'm not pushing it into the array with the period selected from radio buttons. I would like to receive help to understand why of that and what I should modify to make it works properly.
Please check the code I'm sharing controller and view:
searchApp.controller('UserSettingsCtrl', ['$scope', '$q', '$rootScope', 'aiStorage', 'userConfig', 'UserSettingsService', 'WebsiteSource', 'AnalyticsEmailService', 'toaster', '$translate', '$filter', 'ngTableParams',
function($scope, $q, $rootScope, store, userConfig, UserSettingsService, WebsiteSource, AnalyticsEmailService, toaster, $translate, $filter, ngTableParams) {
$scope.init = function() {
$scope.availableLanguages = {
da: 'Dansk',
en: 'English',
sv: 'Svensk'
}
window.scope = $scope
$scope.userInfo = store.get('user')
$scope.loadingAction = false
$scope.selectFlag = false
$scope.subscriptionEnginesFromServer = []
$scope.subscriptionEngines = []
$scope.analyticsEmailSettings = {}
$scope.engines = angular.copy(WebsiteSource.sites)
AnalyticsEmailService.getUserSubscription().then(
function success(response) {
$scope.loadingAction = false
$scope.subscription = response
console.log('response.data', response.data)
$scope.subscriptionEnginesFromServer = populateSubscribedEnginesFromServer(response.data)
getUnselectedEngines()
$scope.analyticsEmailSettings.subscribed = (response.data.length > 0)
},
function error() {})
}
function populateSubscribedEnginesFromServer(data) {
console.log('data', data)
var subscriptionEngines = []
for (var i = 0; i < data.length; i++) {
var subscription = data[i]
var engine = $scope.engines.filter(function(x) {
if (x.id === subscription.engine) {
var index = $scope.engines.indexOf(x)
$scope.engines[index].type = subscription.type
}
return x.id === subscription.engine
})[0]
console.log('engine', engine)
if (engine) subscription.name = engine.name
subscriptionEngines.push(subscription)
}
console.log('subscriptionEngines', subscriptionEngines)
if (subscriptionEngines.length == 0) {
$scope.analyticsEmailSettings.subscription = 'WeeklyAnalytics'
} else {
$scope.analyticsEmailSettings.subscription = subscriptionEngines[0].type
}
return subscriptionEngines
}
// Save for all always the user have to press the save button if wants save no auto save as it is now
$scope.save = function() {
$scope.loadingAction = true
if ($scope.analyticsEmailSettings.subscribed) {
AnalyticsEmailService.updatesubscriptions($scope.subscriptionEnginesFromServer, function success(response) {}, function error() {})
} else {
$scope.analyticsEmailSettings.subscription = 'WeeklyAnalytics'
$scope.subscriptionEnginesFromServer = []
AnalyticsEmailService.updatesubscriptions($scope.subscriptionEnginesFromServer, function success(response) {}, function error() {})
}
UserSettingsService.save({
userId: $scope.userInfo.id
}, $scope.userInfo, function() {
$scope.loadingAction = false
userConfig.setCurrentUserConfig($scope.userInfo)
userConfig.setUserLocale()
store.set('user', $scope.userInfo)
toaster.pop({
type: 'success',
body: $translate.instant('notifications_user_settings_changed_success')
})
}, function() {})
$scope.subscriptionEngines = []
}
// removeSelectedEngines
getUnselectedEngines = function() {
for (var i = 0; i < $scope.engines.length; i++) {
if ($scope.subscriptionEnginesFromServer.filter(function(x) {
return x.engine === $scope.engines[i].id
}).length == 0)
$scope.engines[i].type = ''
}
}
// #todo: consider referring by array key instead of engineId
function updatesubscriptions(engineId, subscriptionType) {
var engine
for (var i = 0; i < $scope.subscriptionEnginesFromServer.length; i++) {
if ($scope.subscriptionEnginesFromServer[i].engine == engineId) {
engine = $scope.subscriptionEnginesFromServer[i]
}
}
engine.type = subscriptionType
engine.engine = engineId
}
$scope.updateSubscriptionType = function(engine) {
for (var i = 0; i < $scope.subscriptionEnginesFromServer.length; i++) {
updatesubscriptions($scope.subscriptionEnginesFromServer[i].engine, $scope.analyticsEmailSettings.subscription)
}
}
$scope.addSubscribedEngine = function(engine) {
$scope.subscriptionEngines = []
engine.type = $scope.analyticsEmailSettings.subscription
$scope.subscriptionEnginesFromServer.push({
type: engine.type,
engine: engine.id,
name: engine.name
})
}
$scope.selectFirstUnsubscribedEngine = function() {
var filtered
filtered = $scope.engines.filter(function(x) {
return x.type == ''
})
filtered = $filter('orderBy')(filtered, 'name')
$scope.engine.current = filtered.length ? filtered[0] : null
}
$scope.removeSubscribedEngine = function(engine) {
engine.type = ''
for (var i = 0; i < $scope.subscriptionEnginesFromServer.length; i++) {
if ($scope.subscriptionEnginesFromServer[i].engine == engine.id) {
$scope.subscriptionEnginesFromServer.splice(i, 1)
}
}
save()
}
}])
View:
<div ng-controller="UserSettingsCtrl" ng-init="init()">
<div class="content">
<header class="flex-container row header">
<div class="flex-1">
<h1 class="flex-1">{{ 'user_settings_title' | translate }}</h1>
</div>
<!--<a class="logout" href ui-sref="account.settings.changepassword">{{ 'user_change_password_menu' | translate }}</a>-->
</header>
<div class="main-edit">
<div class="subsection">
<div class="inputs-container-row full-width">
<div class="input-group full-width">
<div class="inputfield">
<label class="label ng-binding" for="name">
{{ 'user_settings_firstname_label' | translate }}
</label>
<input type="text" name="firstname" ng-model="userInfo.firstName" class="flex-1" ng-class="{'first-letter-to-upper' : userInfo.firstName.length > 0 }" placeholder="{{ 'user_settings_firstname_placeholder' | translate }}">
</div>
</div>
<div class="input-group full-width">
<div class="inputfield">
<label class="label ng-binding" for="name">
{{ 'user_settings_lastname_label' | translate }}
</label>
<input type="text" name="lastname" ng-model="userInfo.lastName" class="flex-1" ng-class="{'first-letter-to-upper' : userInfo.lastName.length > 0 }" placeholder="{{ 'user_settings_lastname_placeholder' | translate }}">
</div>
</div>
</div>
<div class="inputs-container-row full-width">
<div class="inputs-container-row half-width">
<div class="input-group full-width">
<label class="label" for="name">{{ 'user_settings_language_label' | translate }}</label>
<div class="select-group full-width">
<select class="select" id="selectLanguage" ng-model="userInfo.language" ng-options="key as value for (key , value) in availableLanguages"></select>
<label for="selectLanguage"><span class="fa fa-angle-down"></span></label>
</div>
</div>
</div>
<div class="inputs-container-row half-width">
<div class="input-group full-width">
<label class="label" for="name">
{{ 'user_settings_phone_label' | translate }}
</label>
<input type="text" name="lastname" ng-model="userInfo.phoneNumber" placeholder="{{ 'user_settings_phone_placeholder' | translate }}">
</div>
</div>
</div>
</div>
<div class="subsection">
<div class="inputs-container-row half-width">
<div class="input-group full-width">
<label class="label" for="name">
{{ 'user_settings_password_label' | translate }}
<a ui-sref="account.settings.changepassword" class="button button-link--primary button--first">
{{ 'user_settings_password_button' | translate }}...
</a>
</label>
</div>
</div>
</div>
</div>
<div class="flex-container row header">
<div class="flex-1">
<h1 class="flex-1">{{ 'user_settings_emailStatistics_title' | translate }}</h1>
</div>
</div>
<!--||| Subscribe Start |||-->
<div class="main-edit">
<div class="subsection">
<div class="flex-container row">
<div class="radiobutton-group">
<div class="width-140">
<input id="subscribed" type="checkbox" ng-model="analyticsEmailSettings.subscribed" value="subscribed" class="radiobutton">
<label class="label highlight inline no-bottom-margin" for="subscribed">
{{ 'user_settings_emailStatistics_subscribe' | translate }}
</label>
</div>
</div>
</div>
<div ng-show="analyticsEmailSettings.subscribed">
<div class="flex-container row">
<div class="input-group flex-1" ng-switch="analyticsEmailSettings.subscription">
<label class="label" for="name">{{ 'user_settings_emailStatistics_recurrence' | translate }}</label>
<div class="inputs-container-row half-width" name="oftenReportSent">
<span class="radiobutton flex-1" ng-class="{'checked' : analyticsEmailSettings.subscription === 'WeeklyAnalytics'}" name="radio">
<input type="radio" name="WeeklyAnalytics" ng-model="analyticsEmailSettings.subscription" ng-change="updateSubscriptionType()" ng-checked="analyticsEmailSettings.subscription === 'WeeklyAnalytics'" value="WeeklyAnalytics" id="WeeklyAnalytics" ng-required="">
<label for="WeeklyAnalytics">{{ 'user_settings_emailStatistics_weekly' | translate }}</label>
</span>
<span class="radiobutton flex-1" ng-class="{'checked' : analyticsEmailSettings.subscription === 'MonthlyAnalytics'}">
<input type="radio" name="MonthlyAnalytics" ng-model="analyticsEmailSettings.subscription" ng-change="updateSubscriptionType()" ng-checked="analyticsEmailSettings.subscription === 'MonthlyAnalytics'" value="MonthlyAnalytics" id="MonthlyAnalytics" ng-required="">
<label for="MonthlyAnalytics">{{ 'user_settings_emailStatistics_monthly' | translate }}</label>
</span>
</div>
<div> <span style="color:red;" ng-show="analyticsEmailSettings.subscription == null">Please select option</span></div>
</div>
</div>
<h1>Before</h1>
<div ng-if="engines.length == 1">
<ul class="tags tags--inline item-with-inline-buttons">
<li ng-repeat="engine in engines | orderBy:'name'">
{{engine.name}}
<span class="button-icon button--primary button--delete" ng-click="removeSubscribedEngine(engine); selectFirstUnsubscribedEngine()">
<i class="fa fa-trash-o"></i>
</span>
</li>
</ul>
</div>
<h1>after</h1>
<div ng-show="engines.length > 1">
<div class="flex-container row" ng-show="((engines | filter:{type:''}:true).length != 0)">
<div class="input-group full-width">
<label class="label" for="selectEngine">
{{ 'user_settings_emailStatistics_engines_label' | translate }}:
</label>
<div class="half-width inputfield--horizontal" style="margin-bottom: 10px;">
<div class="full-width select-group" ng-if="(engines | filter:{type:''}:true).length > 0">
<select class="select" id="selectEngine" ng-model="$parent.engine.current" ng-options="website.name for website in engines | filter:{type:''}:true | orderBy:'name'" ng-init="$parent.engine.current = (engines | filter:{type:''}:true | orderBy:'name')[0]">
</select>
<label for="selectSubscription"><span class="fa fa-angle-down"></span></label>
</div>
<span ng-show="engines.length == 1">{{(engines | filter:{type:''}:true)[0].name}}</span>
<div id="btnAddWebSitesSubscription" ng-show="engines.length > 0" class="button button--add" ng-click="addSubscribedEngine(engine.current); selectFirstUnsubscribedEngine()"><i class="fa fa-plus"></i></div>
</div>
</div>
</div>
<div ng-model="successMessage" ng-show="showMessage" style="color:green;" class="message fadein fadeout">{{successMessage}}</div>
</div>
<h1 ng-show="subscriptionEnginesFromServer.length > 0 && engines.length > 1">Websites Subscribed</h1>
<div class="flex-container row" ng-if="subscriptionEnginesFromServer.length > 0 && engines.length > 1">
<ul class="tags tags--inline item-with-inline-buttons">
<li ng-repeat="engine in engines | filter:{type:'Analytics'} | orderBy:'name'">
{{engine.name}}
<span class="button-icon button--primary button--delete" ng-click="removeSubscribedEngine(engine); selectFirstUnsubscribedEngine()">
<i class="fa fa-trash-o"></i>
</span>
</li>
</ul>
</div>
</div>
</div>
<footer class="flex-container flex-end row footer">
<button class="button button--primary button--action" ng-click="save();">
<i ng-show="loadingAction" class="fa fa-spinner fa-spinner-custom"></i>
<span ng-show="!loadingAction">{{ 'general_save' | translate }}</span>
</button>
</footer>
</div>
</div>
Be careful of using ng-hide/ng-show as when the partial is 'hidden' it destroys the model (if there are any) contained within itself (so, use ng-if instead).
In your html in the subscription section, you make a call like this:
ng-change="updateSubscriptionType()"
But in your javascript you have:
$scope.updateSubscriptionType = function(engine) {
for (var i = 0; i < $scope.subscriptionEnginesFromServer.length; i++) {
updatesubscriptions($scope.subscriptionEnginesFromServer[i].engine, $scope.analyticsEmailSettings.subscription)
}
}
So it's expecting an 'engine' argument, which you never pass in. But looking at the code you don't use the engine argument anyway; you use the 'engine' property of $scope.subscriptionEnginesFromServer[i] but that's it.
It however, doesn't do anything that I can see, anyway. It loops through an empty array then calls updatesubscriptions() to do something, but it won't actually call it.
Also, the updatesubscriptions() method itself doesn't actually do anything. This is probably why you're not getting anything in your array. I'd suggest modifying your template slightly, because the subscription radio buttons are outside the engines loop, so you won't be able to associate the subscription type with any engine. Once you have done that, then the subscriptions type radio buttons will have access to 'engine', which you can pass in. Modify your method accordingly:
$scope.updateSubscriptionType = function(engine) {
if (!$scope.subscriptionEnginesFromService.includes(engine)) {
$scope.subscriptionEnginesFromService.push(engine);
}
updatesubscriptions(engine, $scope.analyticsEmailSettings.subscription);
}
And also modify the updatesubscriptions() slightly.
In the dynamic input field is there any option to implement plusSign = true only for the last item ?
(function() {
var app = angular.module('managementApp', []);
// var app = angular.module('managementApp', ['ngRoute']);
app.controller('phonebookController', function($scope, $http) {
$scope.dynamicField = function(buttonStatus, inputIndex) {
if (!buttonStatus) {
$scope.currentContact.contacts.push({
"phone": ""
});
} else {
$scope.currentContact.contacts.splice(inputIndex, 1);
}
};
$scope.currentContact = [{
"phone": "07875 506 426"
}, {
"phone": "+91 9895 319991"
}, {
"phone": "+44 7875 506 426"
}];
$scope.dynamicField = function(buttonStatus, inputIndex) {
if (!buttonStatus) {
$scope.currentContact.push({
"phone": ""
});
} else {
$scope.currentContact.splice(inputIndex, 1);
}
};
$scope.checkIndex = function(totalCount, indexCount) {
indexCount++;
// alert(indexCount);
/*if (totalCount === indexCount) {
//alert("last one");
$scope.plusSign = true;
}else{
$scope.plusSign = false;
}*/
};
});
})();
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="container" ng-app="managementApp">
<div class="row" ng-controller="phonebookController">
<div class="form-group" ng-repeat="contact in currentContact" ng-init="checkIndex(currentContact.length, $index);">
<label for="contact-number3" class="col-sm-3 control-label">Contact number {{$index + 1 }}</label>
<div class="col-sm-9">
<div class="input-group">
<input type="tel" class="form-control" placeholder="Contact number {{$index + 1 }}" ng-model="contact.phone">
<span class="input-group-btn">
<button class="btn btn-default" type="button" ng-init="plusSign = true"
ng-click="plusSign = !plusSign; dynamicField(plusSign, $index);">
<i class="glyphicon " ng-class="plusSign ? 'glyphicon-plus' : 'glyphicon-minus'"></i>
</button>
</span>
</div>
</div>
</div>
</div>
</div>
You can use $last inside ng-repeat which is true if the repeated element is last in the iterator. Or you can do it with css only with .row:last-of-type {/**/}.
check $last in your function for example:-
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="container" ng-app="managementApp">
<div class="row" ng-controller="phonebookController">
<div class="form-group" ng-repeat="contact in currentContact" ng-init="checkIndex($last);">
<label for="contact-number3" class="col-sm-3 control-label">Contact number {{$index + 1 }}</label>
<div class="col-sm-9">
<div class="input-group">
<input type="tel" class="form-control" placeholder="Contact number {{$index + 1 }}" ng-model="contact.phone">
<span class="input-group-btn">
<button class="btn btn-default" type="button" ng-init="plusSign = true"
ng-click="plusSign = !plusSign; dynamicField(plusSign, $index);">
<i class="glyphicon " ng-class="plusSign ? 'glyphicon-plus' : 'glyphicon-minus'"></i>
</button>
</span>
</div>
</div>
</div>
</div>
</div>
controller method
$scope.checkIndex = function(last) {
(last === true)
$scope.plusSign = true;
else
$scope.plusSign = false;
};