Close previous table row when clicking on another table row - javascript

I'm fetching data into the table and on clicking any table row it open a nested colspan inside table row. I want to close previous table row if i click on another table row (Like accordion does )
this is a table body structure
<tbody style="cursor:pointer" v-for="(statement,index) in statements">
<tr #click="statementDetail(index,statement.paper_quality_id.id,statement.paper_brand_id.id,statement.paper_size_id.id,statement.thickness)"
>
<td>{{index+1}}</td>
<td>
{{statement.paper_quality_id.paper_quality}} -
{{statement.paper_size_id.length}} X {{statement.paper_size_id.width}} -
{{statement.paper_brand_id.paper_brand}} -
{{statement.thickness}}
</td>
<td>
<div class="row">
<div
class="col-md-4 text-center"
>{{parseInt((statement.in_total_before - statement.total_out_before)/500)}}</div>
<div
class="col-md-4 text-center"
>{{parseInt((statement.in_total_before - statement.total_out_before)%500)}}</div>
</div>
</td>
<td>
<div class="row">
<div
class="col-md-4 text-center"
>{{parseInt((statement.total_sheets_in_range)/500)}}</div>
<div
class="col-md-4 text-center"
>{{parseInt((statement.total_sheets_in_range)%500)}}</div>
</div>
</td>
<td>
<div class="row">
<div
class="col-md-4 text-center"
>{{parseInt((statement.total_outward_range)/500)}}</div>
<div
class="col-md-4 text-center"
>{{parseInt((statement.total_outward_range)%500)}}</div>
</div>
</td>
<td>
<div class="row">
<div class="col-md-4 text-center">
{{
parseInt((((statement.in_total_before - statement.total_out_before) + (statement.total_sheets_in_range)) - statement.total_outward_range)/500)
}}
</div>
<div class="col-md-4 text-center">
{{
parseInt((((statement.in_total_before - statement.total_out_before) + (statement.total_sheets_in_range)) - statement.total_outward_range)%500)
}}
</div>
</div>
</td>
</tr>
This the nested table it appears when we click on table row
<tr :id="'show_'+index" v-if = "index = indexData" >
<td colspan="6">
<table class="table table-hover">
<tr>
<th>Date</th>
<th>Opening</th>
<th>Inward</th>
<th>Outward</th>
<th>Balance</th>
</tr>
<tr v-for="(_statement,index) in statements_details" >
<td>{{_statement.date}}</td>
<td>
<div class="row">
<div
class="col-md-3 text-center"
>{{parseInt((_statement.opening.total_in - _statement.opening.total_out)/500)}}</div>
<div
class="col-md-3 text-center"
>{{parseInt((_statement.opening.total_in - _statement.opening.total_out)%500)}}</div>
</div>
</td>
<td>
<div class="row">
<div class="col-md-3 text-center">{{parseInt((_statement.inward)/500)}}</div>
<div class="col-md-3 text-center">{{parseInt((_statement.inward)%500)}}</div>
</div>
</td>
<td>
<div class="row">
<div class="col-md-3 text-center">{{parseInt((_statement.outward)/500)}}</div>
<div class="col-md-3 text-center">{{parseInt((_statement.outward)%500)}}</div>
</div>
</td>
<td>
<div class="row">
<div
class="col-md-3 text-center"
>{{parseInt((_statement.balance.total_in - _statement.balance.total_out)/500)}}</div>
<div
class="col-md-3 text-center"
>{{parseInt((_statement.balance.total_in - _statement.balance.total_out)%500)}}</div>
</div>
</td>
</tr>
</table>
</td>
</tr>
</tbody>
This is my js file
export default {
data() {
return {
statements: '',
users: [],
ledger_name: '',
paper_details: '',
account_list: false,
//statement Objects
id: '',
start_date: '',
end_date: '',
paper_quality_id: '',
paper_size_id: '',
paper_brand_id: '',
thickness: '',
statements_details: '',
stockIDS: '',
indexData: ''
};
},
created() {
this.fetchData();
},
components: {
appInventoryNavigation: InventoryNavBar,
},
methods: {
// Fetching Ledger Account List
fetchData() {
var vm = this;
axios.get('/ledger/')
.then((response) => {
console.log(response)
vm.users = response.data
}).catch((err) => {
console.log(err)
});
},
//Setting LedgerID In Hidden Input Field
setLedgerID_1(id, name) {
this.account_name = id;
this.account_list = false;
this.id = id;
this.ledger_name = name;
},
call() {
this.account_list = true;
},
//Posting LedgeID
PostLedgerID(e) {
e.preventDefault();
const AccountDetail = {
id: this.id,
start_date: this.start_date + ' 00:00:00.957761',
end_date: this.end_date + ' 00:00:00.957761'
}
var vm = this;
axios.post('/Statement/', AccountDetail)
.then((response) => {
console.log(response)
vm.statements = response.data;
}).catch((err) => {
console.log(err)
});
},
//Show Hide Nested Table
statementDetail(rowid, paper_id, brand_id, size_id, thickness) {
this.indexData = rowid;
alert(this.indexData)
const userDetail = {
account_access_key_id: $('#ledger_id').val(),
start_date: this.start_date + ' 00:00:00.957761',
end_date: this.end_date + ' 00:00:00.957761',
paper_quality_id: paper_id,
paper_brand_id: brand_id,
paper_size_id: size_id,
thickness: thickness
}
axios.post('/StatementDetail/', userDetail)
.then((response) => {
$('#show_' + rowid).toggle();
this.statements_details = response.data;
}).catch((err) => {
console.log(err)
});
}
},
};

Change v-show="indexData === index".
And in your method check if rowid is changed and move this.indexData = rowid; after axios request:
statementDetail(rowid, paper_id, brand_id, size_id, thickness) {
if (rowid !== this.indexData){
const userDetail = {
account_access_key_id: $('#ledger_id').val(),
start_date: this.start_date + ' 00:00:00.957761',
end_date: this.end_date + ' 00:00:00.957761',
paper_quality_id: paper_id,
paper_brand_id: brand_id,
paper_size_id: size_id,
thickness: thickness
}
axios.post('/StatementDetail/', userDetail)
.then((response) => {
$('#show_' + rowid).toggle();
this.statements_details = response.data;
}).catch((err) => {
console.log(err)
});
this.indexData = rowid;
}
}
Good luck.

Related

bind multiple inputs to each other in vuejs to change together

i want multiple text inputs that when i change one of them i want others to change with the same value too . my inputs are generating in a loop of v-for like below :
<tbody>
<variant-item v-for='(variant, index) in variants' :variant="variant" :key="index" :index="index" "></variant-item>
</tbody>
and here the input is getting generated :
<td>
<div class="control-group" :class="[errors.has(variantInputName + '[price]') ? 'has-error' : '']">
<input type="number" v-model="variant.price" :name="[variantInputName + '[price]']" />
<span class="control-error" v-if="errors.has(variantInputName + '[price]')">#{{ errors.first(variantInputName + '[price]') }}</span></div>
</td>
so with this code if i have 2 products for example the result would be like below :
<td><div class="control-group"><input type="number" name="variants[4344][price]" data-vv-as=""price"" step="any" class="control"> <!----></div></td>
.
.
.
.
<td><div class="control-group"><input type="number" name="variants[4345][price]" data-vv-as=""[price"" > <!----></div></td>
now I want this 2 or multiple inputs change together .
#section('css')
#parent
<style>
.table th.price, .table th.weight {
width: 100px;
}
.table th.actions {
width: 85px;
}
.table td.actions .icon {
margin-top: 8px;
}
.table td.actions .icon.pencil-lg-icon {
margin-right: 10px;
}
</style>
#stop
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.variations.before', ['product' => $product]) !!}
<accordian :title="'{{ __('admin::app.catalog.products.variations') }}'" :active="true">
<div slot="body">
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.variations.controls.before', ['product' => $product]) !!}
<button type="button" class="btn btn-md btn-primary" #click="showModal('addVariant')">
{{ __('admin::app.catalog.products.add-variant-btn-title') }}
</button>
<variant-list></variant-list>
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.variations.controls.after', ['product' => $product]) !!}
</div>
</accordian>
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.variations.after', ['product' => $product]) !!}
<modal id="addVariant" :is-open="modalIds.addVariant">
<h3 slot="header">{{ __('admin::app.catalog.products.add-variant-title') }}</h3>
<div slot="body">
<variant-form></variant-form>
</div>
</modal>
#push('scripts')
#parent
<script type="text/x-template" id="variant-form-template">
<form method="POST" action="{{ route('admin.catalog.products.store') }}" data-vv-scope="add-variant-form" #submit.prevent="addVariant('add-variant-form')">
<div class="page-content">
<div class="form-container">
<div v-for='(attribute, index) in super_attributes' class="control-group" :class="[errors.has('add-variant-form.' + attribute.code) ? 'has-error' : '']">
<label :for="attribute.code" class="required">#{{ attribute.admin_name }}</label>
<select v-validate="'required'" v-model="variant[attribute.code]" class="control" :id="attribute.code" :name="attribute.code" :data-vv-as="'"' + attribute.admin_name + '"'">
<option v-for='(option, index) in attribute.options' :value="option.id">#{{ option.admin_name }}</option>
</select>
<span class="control-error" v-if="errors.has('add-variant-form.' + attribute.code)">#{{ errors.first('add-variant-form.' + attribute.code) }}</span>
</div>
<button type="submit" class="btn btn-lg btn-primary">
{{ __('admin::app.catalog.products.add-variant-title') }}
</button>
</div>
</div>
</form>
</script>
<script type="text/x-template" id="variant-list-template">
<div class="table" style="margin-top: 20px; overflow-x: auto;">
<table>
<thead>
<tr>
<th class="sku">{{ __('admin::app.catalog.products.sku') }}</th>
<th>{{ __('admin::app.catalog.products.name') }}</th>
#foreach ($product->super_attributes as $attribute)
<th class="{{ $attribute->code }}" style="width: 150px">{{ $attribute->admin_name }}</th>
#endforeach
<th class="qty">{{ __('admin::app.catalog.products.qty') }}</th>
<th class="price">{{ __('admin::app.catalog.products.price') }}</th>
<th class="weight">{{ __('admin::app.catalog.products.weight') }}</th>
<th class="status">{{ __('admin::app.catalog.products.status') }}</th>
<th class="actions"></th>
</tr>
</thead>
<tbody>
<variant-item v-for='(variant, index) in variants' :variant="variant" :key="index" :index="index" :variant-price.sync="variantPrice" #onRemoveVariant="removeVariant($event)"></variant-item>
</tbody>
</table>
</div>
</script>
<script type="text/x-template" id="variant-item-template">
<tr>
<td>
<div class="control-group" :class="[errors.has(variantInputName + '[sku]') ? 'has-error' : '']">
<input type="text" v-validate="'required'" v-model="variant.sku" :name="[variantInputName + '[sku]']" class="control" data-vv-as=""{{ __('admin::app.catalog.products.sku') }}"" v-slugify/>
<span class="control-error" v-if="errors.has(variantInputName + '[sku]')">#{{ errors.first(variantInputName + '[sku]') }}</span>
</div>
</td>
<td>
<div class="control-group" :class="[errors.has(variantInputName + '[name]') ? 'has-error' : '']">
<input type="text" v-validate="'required'" v-model="variant.name" :name="[variantInputName + '[name]']" class="control" data-vv-as=""{{ __('admin::app.catalog.products.name') }}""/>
<span class="control-error" v-if="errors.has(variantInputName + '[name]')">#{{ errors.first(variantInputName + '[name]') }}</span>
</div>
</td>
<td v-for='(attribute, index) in superAttributes'>
<div class="control-group">
<input type="hidden" :name="[variantInputName + '[' + attribute.code + ']']" :value="variant[attribute.code]"/>
<input type="text" class="control" :value="optionName(variant[attribute.code])" readonly/>
</div>
</td>
<td>
<button style="width: 100%;" type="button" class="dropdown-btn dropdown-toggle">
#{{ totalQty }}
<i class="icon arrow-down-icon"></i>
</button>
<div class="dropdown-list">
<div class="dropdown-container">
<ul>
<li v-for='(inventorySource, index) in inventorySources'>
<div class="control-group" :class="[errors.has(variantInputName + '[inventories][' + inventorySource.id + ']') ? 'has-error' : '']">
<label>#{{ inventorySource.name }}</label>
<input type="text" v-validate="'numeric|min:0'" :name="[variantInputName + '[inventories][' + inventorySource.id + ']']" v-model="inventories[inventorySource.id]" class="control" v-on:keyup="updateTotalQty()" :data-vv-as="'"' + inventorySource.name + '"'"/>
<span class="control-error" v-if="errors.has(variantInputName + '[inventories][' + inventorySource.id + ']')">#{{ errors.first(variantInputName + '[inventories][' + inventorySource.id + ']') }}</span>
</div>
</li>
</ul>
</div>
</div>
</td>
<td>
<div class="control-group" :class="[errors.has(variantInputName + '[price]') ? 'has-error' : '']">
<input type="number" v-validate="'required|min_value:0.0001'" v-model="variant.price" :name="[variantInputName + '[price]']" class="control" data-vv-as=""{{ __('admin::app.catalog.products.price') }}"" step="any"/>
<span class="control-error" v-if="errors.has(variantInputName + '[price]')">#{{ errors.first(variantInputName + '[price]') }}</span>
</div>
</td>
<td>
<div class="control-group" :class="[errors.has(variantInputName + '[weight]') ? 'has-error' : '']">
<input type="number" v-validate="'required|min_value:0.0001'" v-model="variant.weight" :name="[variantInputName + '[weight]']" class="control" data-vv-as=""{{ __('admin::app.catalog.products.weight') }}"" step="any"/>
<span class="control-error" v-if="errors.has(variantInputName + '[weight]')">#{{ errors.first(variantInputName + '[weight]') }}</span>
</div>
</td>
<td>
<div class="control-group">
<select type="text" v-model="variant.status" :name="[variantInputName + '[status]']" class="control">
<option value="1" :selected="variant.status">{{ __('admin::app.catalog.products.enabled') }}</option>
<option value="0" :selected="!variant.status">{{ __('admin::app.catalog.products.disabled') }}</option>
</select>
</div>
</td>
<td class="actions">
<a :href="['{{ route('admin.catalog.products.index') }}/edit/' + variant.id]"><i class="icon pencil-lg-icon"></i></a>
<i class="icon remove-icon" #click="removeVariant()"></i>
</td>
</tr>
</script>
<script>
$(document).ready(function () {
Vue.config.ignoredElements = [
'variant-form',
'variant-list',
'variant-item'
];
});
var super_attributes = #json(app('\Webkul\Product\Repositories\ProductRepository')->getSuperAttributes($product));
var variants = #json($product->variants);
Vue.component('variant-form', {
data: function() {
return {
variant: {},
super_attributes: super_attributes
}
},
template: '#variant-form-template',
created: function () {
this.resetModel();
},
methods: {
addVariant: function (formScope) {
this.$validator.validateAll(formScope).then((result) => {
if (result) {
var this_this = this;
var filteredVariants = variants.filter(function(variant) {
var matchCount = 0;
for (var key in this_this.variant) {
if (variant[key] == this_this.variant[key]) {
matchCount++;
}
}
return matchCount == this_this.super_attributes.length;
})
if (filteredVariants.length) {
this.$parent.closeModal();
window.flashMessages = [{'type': 'alert-error', 'message': "{{ __('admin::app.catalog.products.variant-already-exist-message') }}" }];
this.$root.addFlashMessages()
} else {
var optionIds = [];
for (var key in this_this.variant) {
optionIds.push(this_this.variant[key]);
}
variants.push(Object.assign({
sku: '{{ $product->sku }}' + '-variant-' + optionIds.join('-'),
name: '',
price: 0,
weight: 0,
status: 1
}, this.variant));
this.resetModel();
this.$parent.closeModal();
}
}
});
},
resetModel: function () {
var this_this = this;
this.super_attributes.forEach(function(attribute) {
this_this.variant[attribute.code] = '';
})
}
}
});
Vue.component('variant-list', {
template: '#variant-list-template',
inject: ['$validator'],
data: function() {
return {
variants: variants,
variantPrice:0,
old_variants: #json(old('variants')),
superAttributes: super_attributes
}
},
created: function () {
var index = 0;
for (var key in this.old_variants) {
var variant = this.old_variants[key];
if (key.indexOf('variant_') !== -1) {
var inventories = [];
for (var inventorySourceId in variant['inventories']) {
inventories.push({'qty': variant['inventories'][inventorySourceId], 'inventory_source_id': inventorySourceId})
}
variant['inventories'] = inventories;
variants.push(variant);
} else {
for (var code in variant) {
if (code != 'inventories') {
variants[index][code] = variant[code];
} else {
variants[index][code] = [];
for (var inventorySourceId in variant[code]) {
variants[index][code].push({'qty': variant[code][inventorySourceId], 'inventory_source_id': inventorySourceId})
}
}
}
}
index++;
}
},
methods: {
removeVariant: function(variant) {
let index = this.variants.indexOf(variant)
this.variants.splice(index, 1)
},
}
});
Vue.component('variant-item', {
template: '#variant-item-template',
props: ['variantPrice','index', 'variant'],
inject: ['$validator'],
data: function() {
return {
inventorySources: #json($inventorySources),
inventories: {},
totalQty: 0,
superAttributes: super_attributes
}
},
created: function () {
var this_this = this;
this.inventorySources.forEach(function(inventorySource) {
this_this.inventories[inventorySource.id] = this_this.sourceInventoryQty(inventorySource.id)
this_this.totalQty += parseInt(this_this.inventories[inventorySource.id]);
})
},
computed: {
variantInputName: function () {
if (this.variant.id)
return "variants[" + this.variant.id + "]";
return "variants[variant_" + this.index + "]";
}
},
methods: {
removeVariant: function () {
this.$emit('onRemoveVariant', this.variant)
},
onVariantPriceInput(event) {
this.$emit('update:variantPrice', Number(event.target.value));
},
optionName: function (optionId) {
var optionName = '';
this.superAttributes.forEach(function(attribute) {
attribute.options.forEach(function(option) {
if (optionId == option.id) {
optionName = option.admin_name;
}
});
})
return optionName;
},
sourceInventoryQty: function (inventorySourceId) {
if (! Array.isArray(this.variant.inventories))
return 0;
var inventories = this.variant.inventories.filter(function(inventory) {
return inventorySourceId === parseInt(inventory.inventory_source_id);
})
if (inventories.length)
return inventories[0]['qty'];
return 0;
},
updateTotalQty: function () {
this.totalQty = 0;
for (var key in this.inventories) {
this.totalQty += parseInt(this.inventories[key]);
}
}
}
});
</script>
#endpush
If it is your objective to have a single price which is shared by all variants, then I would advise against having a price property per variant Object. variant.price suggests a price per variant. I would create a separate data property, say variantPrice that would be passed to each instance of the variant-item component.
(As an aside: If there is a single price that is to be shared by all variant-item components then it may be confusing to your users that you render a price input field per variant-item instead of having a single input field.)
One way to synchronize a value with multiple child components, and assuming you are using a version of Vue >= 2.3 and < 3, is to use the .sync modifier.
Your parent component - the one that references the variants Array - would have a new data property for variantPrice. Here is an example where the parent is the root Vue component:
new Vue({
components: {
variantItem: VariantItem
},
data() {
return {
variantPrice: 0,
variants: [
{
inputName: 'VariantOne'
},
{
inputName: 'VariantTwo'
}
]
};
},
el: "#App"
});
The template of the parent (root) would pass variantPrice as a prop to each variant-item instance using the .sync modifier which will bind the value of variantPrice to the update:variantPrice event emitted by the child. The template would look like:
<div id="App">
<variant-item v-for="(variant, index) in variants" :key="index" :variant="variant" :variant-price.sync="variantPrice"></variant-item>
</div>
Next, we must ensure that our VariantItem component takes a variantPrice as a prop and emits the update:variantPrice event when the input field is modified by the user:
const VariantItem = Vue.component('variant-item', {
methods: {
onVariantPriceInput(event) {
this.$emit('update:variantPrice', Number(event.target.value));
}
},
props: {
variant: {
required: true,
type: Object
},
variantPrice: {
required: true,
type: Number
}
},
template: '#VariantItemTemplate'
});
The template for this component would become:
<div>
<label :for="variant.inputName">{{ variant.inputName }}</label>
<input :id="variant.inputName" :name="variant.inputName" :value="variantPrice" #input="onVariantPriceInput" type="number">
</div>
I have created a fiddle for your reference.

My html data isn't displayed because of my javascript

So i started to build a basic website as a practice, and i got until i have a basic html, containing a table of informations, and a form, where you can add to the html through javascript.
My html looks like this
<body>
<hr>
<p class="display-4 text-center">Termék lista</p>
<table class="table">
<thead>
<tr>
<th scope="col">Termék Név</th>
<th scope="col">Termék Azonosító</th>
<th scope="col">Termék Ár</th>
<th scope="col">Termék leírás</th>
<th scope="col">Raktáron</th>
<th scope="col">Törlés</th>
</tr>
</thead>
<tbody id="tbody">
<tr>
<td>mangó</td>
<td>1</td>
<td>499 Ft</td>
<td>Gyümi</td>
<td>Van</td>
<td> <button class="delete btn btn-primary">X</button> </td>
</tr>
</tbody>
</table>
<div class="container mt-5">
<div class="bg-success p-5">
<form id="input-form">
<p class="display-4 text-center">Termékek hozzáadása</p>
<div class="form-row">
<div class="form-group col-md-6">
<label for="inputProduct">Termék</label>
<input type="text" class="form-control" id="inputProduct" name="productName">
</div>
<div class="form-group col-md-6">
<label for="inputCode">Termék Azonosító</label>
<input type="number" class="form-control" id="inputCode" name="productCode">
</div>
</div>
<div class="form-group">
<label for="inputPrice">Termék Ára</label>
<input type="number" class="form-control" id="inputPrice" name="productPrice">
</div>
<div class="form-row">
<div class="form-group col-md-8">
<label for="inputDesc">Termék Leírás</label>
<select id="inputDesc" name="inputDesc">
<option value="Gyümölcs">Gyümölcs</option>
<option value="Zöldség">Zöldség</option>
</select> </div>
<div class="form-group col-md-4">
<label for="inputSupply">Raktáron </label>
<select id="inputSupply" name="productSupply">
<option value="Van">Van</option>
<option value="Nincs">Nincs</option>
</select>
</div>
</div>
<button id="submit-button" type="submit" class="btn btn-primary">Hozzáadás</button>
</form>
</div>
</div>
And this is my javascript code so far:
var products = [
{
productName:"körte",
productCode: 2,
productPrice: 30,
productDesc: "Gyümi",
productSupply: "Nincs",
productId: 1
},
{
productName: "répa",
productCode: 3,
productPrice: 20,
productDesc: "Gyümi",
productSupply: "Van",
productId: 5
},
{
productName: "paradicsom",
productCode: 4,
productPrice: 50,
productDesc: "Gyümi",
productSupply: "Nincs",
productId: 6
}
]
var table = '<tbody>'
for( i = 0; i < products.length; i++){
table += `<tr>`;
table += `<td>` + products[i].productName + `</td>`;
table += `<td>` + products[i].productCode + `</td>`;
table += `<td>` + products[i].productPrice + `</td>`;
table += `<td>` + products[i].productDesc + `</td>`;
table += `<td>` + products[i].productSupply + `</td>`;
table += `<td> <button class="delete btn btn-primary" id="${products[i].productId}">X</button> </td>`
table += '</tbody>';
}
document.getElementById('tbody').innerHTML = table;
const tBody = document.getElementById("tbody")
tBody.addEventListener("click", function(x){
console.log("remove from tomb");
console.log(x.target);
console.log("gomb id: " + x.target.id);
for (let i = 0; i < products.length; i++) {
console.log("tomb i id: " + products[i].productId);
if (x.target.id == products[i].productId) {
console.log("removed");
products.splice(i, 1);
}
}
if(x.target.classList.contains("delete")) {
x.target.parentElement.parentElement.remove();
}
console.log(products);
})
const productInput = document.getElementById("inputProduct");
const codeInput = document.getElementById("inputCode");
const priceInput = document.getElementById("inputPrice");
const descInput = document.getElementById("inputDesc");
const supplyInput = document.getElementById("inputSupply");
const submitButton = document.getElementById("submit-button");
const addProduct = (ev) => {
ev.preventDefault();
let newProduct ={
productName: document.getElementById("inputProduct").value,
productCode: document.getElementById("inputCode").value,
productPrice: document.getElementById("inputPrice").value,
productDesc: document.getElementById("inputDesc").value,
productSupply: document.getElementById("inputSupply").value,
productId: Date.now()
}
let newRow = document.createElement("tr");
newRow.innerHTML += `
<td>${newProduct.productName}</td>
<td>${newProduct.productCode}</td>
<td>${newProduct.productPrice}</td>
<td>${newProduct.productDesc}</td>
<td>${newProduct.productSupply}</td>
<td> <button class="delete btn btn-primary" id="${newProduct.productId}">X</button> </td>`
tBody.appendChild(newRow);
products.push(newProduct);
document.querySelector('form').reset();
console.warn("added", {products});
}
document.addEventListener("DOMContentLoaded", ()=>{
submitButton.addEventListener("click", addProduct)
})
The problem is, as you can see i already have a product in the html, but i think my javascript for function, which displays the data from the .js overwrited the data from the html, thus displaying only the 3 products from javascript var = products. How can i have both the html data and the javascript data displayed simultaneously, so i have all 4 products when i open my .html?
Just modify this line as following. Hope to help, my friend :))
document.getElementById('tbody').innerHTML += table;
Here is the output:
http://jsfiddle.net/3zd0y64n/

how to add auto complete value to the list?

<div class="maincontent">
<div ng-app="autocompleteCustomTemplateDemo" ng-controller="DemoCtrl as ctrl" class="container container1">
<div class="row">
<div class="col-lg-12 col-sm-12">
<h4><strong> Service</strong></h4>
</div>
</div>
<div class="row">
<div class="col-md-12">
<md-content layout-padding layout="column">
<form ng-submit="$event.preventDefault()">
<md-autocomplete ng-disabled="ctrl.isDisabled" md-no-cache="ctrl.noCache" md-selected-item="ctrl.selectedItem" md-search-text- change="ctrl.searchTextChange(ctrl.searchText)" md-search-text="ctrl.searchText" md-selected-item-change="ctrl.selectedItemChange(item)"
md-items="item in ctrl.querySearch(ctrl.searchText)" md-item-text="item.product_name" md-min-length="0" placeholder="Pick an Angular repository" md-menu-class="autocomplete-custom-template">
<md-item-template>
<span class="item-title">
<span> {{item.product_gid}} </span>
</span>
<span class="item-metadata" ng-model="g1" ng-click="type(g1)">
<span>
<strong>{{item.product_name}}</strong>
</span>
</span>
</md-item-template>
</md-autocomplete>
<div class="row">
<div class="col-md-12 text-right">
<md-button ng-click="add()">ADD</md-button>
</div>
</div>
<br/>
<div class="row table-responsive" ng-show="show_servicelist">
<div class="col-md-12 col-lg-12 col-sm-12">
<table class="table table-striped table-bordered table-condensed table-hover md-primary" md-progress="deferred">
<thead class="header">
<tr style="text-align:center">
<th>S No</th>
<th>product name</th>
<th>Quantity</th>
<th style="text-align:center">Amount</th>
</tr>
</thead>
<tbody>
<tr>
<td ng-model="dept_name">{{$index + 1}}</td>
<td>
{{ctrl.selectedItem.product_name}}
</td>
<td style="text-align:center">
<input ng-model="tobuy_remark" />
</td>
<td style="text-align:center">
<input ng-model="tobuy_remarks" />
</td>
</tr>
</tbody>
</table>
<div class="row">
<div class="col-md-12 text-right">
<md-button>Submit</md-button>
</div>
</div>
</div>
</div>
</form>
</md-content>
</div>
</div>
</div>
</div>
JS
(function() {
'use strict';
angular
.module('autocompleteCustomTemplateDemo', ['ngMaterial'])
.controller('DemoCtrl', DemoCtrl);
function DemoCtrl($timeout, $q, $log, $scope) {
var self = this;
$scope.add = function() {
$scope.show_servicelist = true;
$scope.service = [];
alert(JSON.stringify(self.repos));
$scope.service.push({
product_name: self.repos.product_name
});
}
self.simulateQuery = false;
self.isDisabled = false;
self.repos = loadAll();
self.querySearch = querySearch;
self.selectedItemChange = selectedItemChange;
self.searchTextChange = searchTextChange;
function querySearch(query) {
var results = query ? self.repos.filter(createFilterFor(query)) : self.repos,
deferred;
if (self.simulateQuery) {
deferred = $q.defer();
$timeout(function() {
deferred.resolve(results);
}, Math.random() * 1000, false);
return deferred.promise;
} else {
return results;
}
}
function searchTextChange(text) {
$log.info('Text changed to ' + text);
}
function selectedItemChange(item) {
$log.info('Item changed to ' + JSON.stringify(item));
}
function loadAll() {
var repos = [{
'product_gid': '1',
'product_name': 'stabilizer',
'forks': '16,175',
}, {
'product_gid': '2',
'product_name': 'stand',
'forks': '760',
}, {
'product_gid': '3',
'product_name': 'ac',
'forks': '1,241',
},
];
return repos.map(function(repo) {
repo.value = repo.product_name.toLowerCase();
return repo;
});
}
function createFilterFor(query) {
var lowercaseQuery = angular.lowercase(query);
return function filterFn(item) {
return (item.value.indexOf(lowercaseQuery) === 0);
};
}
}
})();
I'm running the following code to display the value in the autocomplete after selecting the add button. I need the value to list one after another after clicking the add button. I have used a material for this. please guide me, and modify the code. The above code just displays the list empty, how to store a value in the list and allocate in order.
I'll change 2 functions for you, it should work.
first thing create the array globally.
self.repos = [{
'product_gid': '1',
'product_name': 'stabilizer',
'forks': '16,175',
}, {
'product_gid': '2',
'product_name': 'stand',
'forks': '760',
}, {
'product_gid': '3',
'product_name': 'ac',
'forks': '1,241',
},
];
function loadAll() {
return self.repos.map(function(repo) {
repo.value = repo.product_name.toLowerCase();
return repo;
});
}
add(object) {
self.repos.push(object);
self.loadAll();
}

Angular foreach - null values

I am having an issue where when I try to select multiple devices and add them to a group, the array of selected devices($scope.deviceIDs.push) is not getting the values. Can anyone see the issue or suggest a different method. I used http://www.dotnetawesome.com/2015/12/multiselect-dropdown-with-checkbox-in-angularjs.html as template for the service I built.
Here is the angular code.
var MyApp = angular.module('MyApp', ['ui.bootstrap', 'angularjs-dropdown-multiselect']);
MyApp.controller('GroupsController', ['GroupsService', '$scope', '$log', '$uibModal',
function (GroupsService, $scope, $log, $uibModal) {
$scope.groupSelected = [];
$scope.location = '';
$scope.groupguid = '';
$scope.newGroupName = '';
$scope.devicesNotinGroup = [];
$scope.newGroupAddMember = 'false';
$scope.isCollapsed = false;
$scope.groupSelected.GroupID = 0;
$scope.SelectedDevices = [];
$scope.deviceIDs = [];
$scope.dropdownSetting = {
scrollableHeight: '200px',
scrollable: true,
enableSearch: true
}
// Populate Jobs
GroupsService.GetDeviceList().then(function (d) {
$scope.GroupList = d.data;
console.log(d.data)
}, function (error) {
alert('Error!');
});
$scope.showChilds = function (item) {
$scope.grouplist = [];
item.active = !item.active;
console.log("here item=" + item.GroupName + " active=" + item.GroupName.active);
grouplist = item.SubGroup;
};
$scope.showInfoForGroup = function (item) {
console.log("item = " + item + "Count = " + item.DeviceCount);
GroupsService.GetGroupDeviceInformation(item).then(function (d) {
$scope.groupSelected = d.data.devicegroupitem;
//$scope.devicesNotinGroup = d.data.devicesnotingroup;
angular.forEach(d.data.devicesnotingroup, function (value, index) {
$scope.devicesNotinGroup.push({ label: value.HostName, id: value.HostName });
});
//console.log($scope.devicesNotinGroup)
})
}, function (error) {
console.log("item = " +item + "Count = " + groupSelected.DeviceCount);
};
$scope.DeleteDeviceFromGroup = function (deviceguid, groupguid ) {
console.log("DeviceGuid = " + deviceguid + " GroupGuid = " + groupguid);
GroupsService.DeleteDeviceFromList(deviceguid, groupguid).then(function (d) {
$scope.groupSelected = d.data;
})
}
$scope.AddDeviceToGroup = function (hostname, groupguid) {
GroupsService.AddDeviceToGroup(hostname, groupguid).then(function (d) {
$scope.showInfoForGroup(dt.guid);
//$scope.groupSelected = d.data.devicegroupitem;
//$scope.devicesNotinGroup = d.data.devicesnotingroup;
$scope.newGroupAddMember = 'false';
})
}
$scope.SubmitMultipleDevices = function (groupguid){
$scope.deviceIDs = [];
console.log($scope.SelectedDevices);
angular.forEach($scope.SelectedDevices = function (value) {
$scope.deviceIDs.push({ dname: value.HostName, dguid: groupguid } );
});
console.log('device ids ');
console.log($scope.deviceIDs);
var data = { deviceIDs: deviceIDs };
console.log(data);
angular.toJson(data);
GroupsService.SubmitMultiDevicesToGroup(data)
.success(function () {
})
.error(function (error) {
});
}
$scope.CreateGroup = function (groupID, groupName, newGroupAddMember) {
angular.isUndefinedOrNull = function (groupID) {
return angular.isUndefined(groupID) || groupID === null
}
$scope.GroupList = '';
console.log("check value equals" + groupID)
GroupsService.CreateSubGroup(groupID, groupName, newGroupAddMember).then(function (d) {
$scope.GroupList = d.data;
$scope.newGroupName = '';
$scope.newGroupAddMember = false;
})
}
$scope.DeleteGroup = function (groupID) {
$scope.GroupList = '';
GroupsService.DeleteSubGroup(groupID).then(function (d){
$scope.GroupList = d.data;
$scope.newGroupName = '';
})
}
}])
MyApp.factory('GroupsService', function ($http) { // explained about factory in Part2
var fac = {};
fac.GetDeviceList = function () {
return $http.get('/DeviceGroups/getgrouptree')
}
fac.GetGroupDeviceInformation = function (guid) {
return $http.get('/DeviceGroups/GetGroupDeviceInfo?groupguid=' + guid)
}
fac.DeleteDeviceFromList = function (deviceguid, groupguid) {
return $http.get('/DeviceGroups/DeleteDeviceFromGroup?deviceguid='+ deviceguid + "&groupguid=" + groupguid)
}
fac.AddDeviceToGroup = function (hostname, groupguid) {
return $http.get('/DeviceGroups/AddDeviceToGroup?hostname=' + hostname + "&groupguid=" + groupguid)
}
fac.CreateSubGroup = function (groupID, groupName, newGroupAddMember) {
return $http.get('/DeviceGroups/CreateGroup?GroupID=' + groupID + "&groupName=" + groupName + "&AddMember=" + newGroupAddMember)
}
fac.DeleteSubGroup = function (groupID) {
return $http.get('/DeviceGroups/DeleteGroup?GroupID=' + groupID)
}
fac.SubmitMultiDevicesToGroup = function (data) {
return $http.post('/DeviceGroups/AddMultipleDevicesToGroup', data)
}
return fac;
});
Here is the view code:
#model List<NetworkCafe.Models.DeviceGroup>
#{
ViewBag.Title = "Groups";
}
<style>
#clickable:hover {
cursor: pointer;
}
.body-content{padding-top:50px}
.checkbox{padding:0;margin:0;}
.dropdown-menu{overflow:auto !important;}
.form-group div{display:inline-block; margin-right:10px}
</style>
<link rel="stylesheet" href="../Content/font-awesome.min.css">
<div class="container" style="width:90%" ng-app="MyApp" ng-controller="GroupsController">
<div class="col-lg-3">
<div ng-class="dropdown" class="panel panel-warning">
<div class="panel-heading">
Tree List of Groups
</div>
<div class="panel-body">
<script type="text/ng-template" id="tree-structure">
<span>
<span id="clickable" ng-class="{'glyphicon glyphicon-chevron-up':(!dt.AddMembers) && (!dt.active), 'glyphicon glyphicon-chevron-down':(!dt.AddMembers) && (dt.active), 'childElement':(dt.AddMembers)}" ng-click="showChilds(dt)"></span>
<span id="clickable" ng-click="showInfoForGroup(dt.guid)"> {{dt.GroupName}} </span>
</span>
<ul ng-if="dt.AddMembers">
#*<li>Device Count: {{dt.DeviceCount}}</li>
<li>Total Ports: {{dt.TotalPortCount}}</li>
<li>Open Ports: {{dt.OpenPortCount}}</li>
<li>Reserved Ports: {{dt.ReservedPortCount}}</li>
<li>Percent Used: {{dt.PercentUsed}}</li>*#
#*<li><button ng-click="href"</li>*#
</ul>
<ul style="list-style: none" ng-show="dt.active" class="childElement">
<li ng-repeat="dt in dt.SubGroup" ng-include="'tree-structure'">
</li>
</ul>
</script>
</div>
<ul style="list-style: none" ng-class="list-group-item" class="parentList">
<li ng-repeat="dt in GroupList" ng-include="'tree-structure'" style="list-style: none">
</li>
</ul>
</div>
</div>
<div class="col-lg-3">
<div class="panel panel-info">
<div class="panel-heading">
<h3 class="panel-title">Group {{groupSelected.GroupName}} Information</h3>
</div>
<div class="panel-body">
<span ng-hide="!groupSelected.AddMembers">
This group has devices and can not have subgroups.
</span>
<table class="table table-striped table-hover" ng-hide="!groupSelected.AddMembers">
<tr>
<td>Device Count: </td>
<td></td>
<td>{{groupSelected.DeviceCount}}</td>
</tr>
<tr>
<td>Total Ports: </td>
<td></td>
<td>{{groupSelected.TotalPortCount}}</td>
</tr>
<tr>
<td>Open Ports: </td>
<td></td>
<td>{{groupSelected.OpenPortCount}}</td>
</tr>
<tr>
<td>Reserved Ports: </td>
<td></td>
<td>{{groupSelected.ReservedPortCount}}</td>
</tr>
<tr>
<td>Percent Used:</td>
<td></td>
<td>{{groupSelected.PercentUsed}}</td>
</tr>
</table>
<span ng-hide="groupSelected.AddMembers">
This group has subgroups and can not have members.<br /><br />
<label>CREATE SUBGROUP</label><br />
<input ng-model="newGroupName" placeholder="Group Name" /><br />
<label>Group Type</label><br />
<input type="checkbox" ng-model="newGroupAddMember" ng-checked="!newGroupAddMember" />Group will be used for Device.<br />
<button type="submit" class="btn btn-success" ng-click="CreateGroup(groupSelected.GroupID, newGroupName, newGroupAddMember)">Submit</button><br />----------------------- <br />
</span>
<span>
<a class="btn btn-danger" ng-click="DeleteGroup(groupSelected.GroupID)">Danger Delete Group </a> <br />
Delete Group. This will delete all subgroups and devices under this group.
</span>
</div>
</div>
</div>
<div class="col-lg-6" ng-hide="!groupSelected.AddMembers">
<div class="panel panel-success">
<div class="panel-heading">
<h3 class="panel-title">Device List</h3>
</div>
<div class="panel-body">
<table class="table table-striped table-hover ">
<tr>
<th></th>
<th>Device Name</th>
<th>Total Ports</th>
<th>Open Ports</th>
<th>Reserved Ports</th>
<th>Percent Used</th>
</tr>
<tr ng-repeat="dl in groupSelected.DeviceList">
<td> <i id="clickable" class="fa fa-times" ng-click="DeleteDeviceFromGroup(dl.guid, groupSelected.guid)"></i> </td>
<td>{{dl.DeviceName}}</td>
<td>{{dl.TotalPortCount}}</td>
<td>{{dl.OpenPortCount}}</td>
<td>{{dl.ReservedPortCount}}</td>
<td>{{dl.PercentUsed}}</td>
</tr>
<tr>
<td></td>
</tr>
</table>
#*<ul class="nav navbar-nav">
<li class="dropdown">
----------Add Device from Switch List----------<span class="caret"></span>
<ul class="dropdown-menu" role="menu">
<li ng-repeat="sl in devicesNotinGroup">
<span>
<i id="clickable" class="fa fa-plus-square" ng-click="AddDeviceToGroup(sl.HostName, groupSelected.guid)"></i> {{sl.HostName}} {{sl.Site}} {{sl.Zone}}
</span>
</li>
</ul>
</li>
</ul>*#
<form class="form-inline" name="myForm" role="form" ng-submit="SubmitMultipleDevices(groupSelected.guid)">
<div class="form-group">
<label>Add Devices to Group: </label>
#* Directive *#
<div ng-dropdown-multiselect="" extra-settings="dropdownSetting" options="devicesNotinGroup" selected-model="SelectedDevices" checkboxes="true"></div>
</div>
<br />
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
</div>
</div>
#section scripts{
<script src="~/Scripts/angular-1.4.9/ui-bootstrap-tpls-1.1.2.min.js"></script>
<script src="~/Scripts/AngularControllers/DeviceGroupsV2.js"></script>
<script src="~/Scripts/angular-1.4.9/angularjs-dropdown-multiselect.min.js"></script>
<script src="~/Scripts/angular-1.4.9/lodash.js"></script>
}
Your forEach loop is incorrect.
angular.forEach($scope.SelectedDevices = function (value) {
$scope.deviceIDs.push({ dname: value.HostName, dguid: groupguid } );
});
should be :
angular.forEach($scope.SelectedDevices, function (value) {
$scope.deviceIDs.push({ dname: value.HostName, dguid: value.groupguid } );
});

Filtering in nested array

I have a nested data structure mapped to array in knockout JS:
class Departments{
string DepartmentName;
List<Group> groups
}
class Group{
string groupName;
List<Person> persons;
}
class Person{
String Firsname;
string LastName;
}
I fetched data from server and show them in UI successfully. But I want convert the array to a computed one in knockoutJS and filter it by FirstName and LastName. It's worthy to mention I have bound self.search_FirstName and self.search_LastName to two different inputs. HTML code for binding data is as follow:
<div class="form-group">
<input type="text" class="text-right text-success input-lg" placeholder="Name" data-bind="value:search_FirstName, valueUpdate: 'afterkeydown'" />
</div>
<div class="panel-group" id="accordion" data-bind="foreach: Profiles" role="tablist" aria-multiselectable="true">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title" data-bind="text: DepartmentName"></h4>
</div>
<div class="panel-collapse collapse in">
<div class="panel-body">
<table data-bind="foreach: { data: GroupVMs }" class="table table-responsive col-lg-12 col-sm-12 col-md-12">
<tbody>
<tr><td class="groups" data-bind="text: GroupName"></td></tr>
<tr>
<td>
<table data-bind="foreach: { data: PersonPhonesVMs }" class="table table-striped table-responsive col-lg-12 col-sm-12 col-md-12">
<tr>
<td class="col-lg-1 col-sm-1 col-md-1" data-bind="text: Prefix"></td>
<td class="col-lg-2 col-sm-2 col-md-2" data-bind="text: FirstName"></td>
<td class="col-lg-3 col-sm-3 col-md-3" data-bind="text: LastName"></td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
Now I want during typing in the text box search_FirstName data automatically be filtered. Right Now I can filter records based on DepartmentName with the following code:
self.Profiles = ko.computed(function () {
return ko.utils.arrayFilter(self.BackupProfiles(), function (rec) {
return (
(self.search_FirstName().length == 0 || rec.DepartmentName.indexOf(self.search_FirstName()) > -1)
);
});
});
Does anyone has any idea for filtering records based on firstname and lastname fields?
I have created a fiddle for you. The computed at the heart of it builds up a structure like the Profiles structure, but only including the matched records.
vm.filteredProfiles = ko.computed(function () {
var first = vm.search_FirstName().toLocaleLowerCase();
if (first === '') return vm.Profiles();
var result = [];
ko.utils.arrayForEach(vm.Profiles(), function (dept) {
var groupsMatched = [];
ko.utils.arrayForEach(dept.GroupVMs(), function (group) {
var personsMatched = [];
ko.utils.arrayForEach(group.PersonPhonesVMs(), function (person) {
if (person.FirstName().toLocaleLowerCase().indexOf(first) > -1) {
personsMatched.push(person);
}
});
if (personsMatched.length > 0) {
groupsMatched.push({
GroupName: group.GroupName,
PersonPhonesVMs: personsMatched
});
}
});
if (groupsMatched.length > 0) {
result.push({
DepartmentName: dept.DepartmentName,
GroupVMs: groupsMatched
});
}
});
return result;
});
If I understand correctly, you want to "flatten" the entire structure, so that you have an array of people with with DepartmentName and GroupName fields. For the computed to work, each level of your original structure must be observableArrays. The computed would be something like:
var flattenedPeople = ko.computed(function () {
var result = [];
ko.utils.arrayForEach(self.BackupProfiles(), function (dept) {
ko.utils.arrayForEach(dept.groups(), function (group) {
ko.utils.arrayForEach(group.persons(), function (person) {
result.push({
DepartmentName: dept.DepartmentName,
GroupName: group.GroupName,
FirstName: person.FirstName,
LastName: person.LastName
});
});
});
return result;
});
Then you could make a computed that would match on FirstName and/or Lastname:
self.filteredPeople = ko.computed(function () {
var first = self.search_FirstName(),
last = self.search_LastName();
return ko.utils.arrayFilter(flattenedPeople(), function (rec) {
return ( first === '' || rec.FirstName === first ) &&
(last === '' || rec.LastName === last );
});
});

Categories

Resources