Angular 7 setting selected value not firing change event - angular7

I have one single selection drop down and multi select drop down. Both is having dynamic value.
What I am doing is the I am clicking on edit button it shows modal inside modal there is select drop-downs of module and multi select of actions.
I am dynamically selecting module name it works perfectly but dependent multi-select is not working. I think single select is not firing change event.
HTML:
<div class="col-md-12">
<label for="module">Select Module</label>
<select class="form-control" (change)="onChangeModuleDD($event)" name="moduleSelection" required>
<option value="">-- Select Module --</option>
<option *ngFor="let module of allModuleData" [value]="module | json" [selected]="module.name == usermodule">{{
module.name
}}</option>
</select>
</div>
<div class="col-md-12">
<label for="actions">Select Actions/Charts</label>
<ng-multiselect-dropdown [placeholder]="'-- Select Action/Charts --'" [data]="dropdownList" [settings]="dropdownSettings"
(onSelect)="onItemSelect($event)" name="actionSelection" (onDeSelect)="OnItemDeSelect($event)"
(onSelectAll)="onSelectAll($event)" (onDeSelectAll)="onDeSelectAll($event)">
</ng-multiselect-dropdown>
</div>
COMPONENT:
onChangeModuleDD(event) {
this.selectedItems = [] // empty selected action array
this.dropdownList = []
let value = event.target.value
if (value) {
let parsedValue = JSON.parse(value)
this.usermodule = parsedValue.name
if (parsedValue.hasCRUD == 0) {
this.userListingApi.fetchAllDashboardAction().subscribe(res => {
this.dropdownList = []
for (let i = 0; i < res['data'].length; i++) {
this.dropdownList.push(res['data'][i])
}
})
} else {
this.userListingApi.fetchAllCRUDAction().subscribe(res => {
this.dropdownList = []
for (let i = 0; i < res['data'].length; i++) {
this.dropdownList.push(res['data'][i])
}
})
}
} else {
console.log('Nothing to display')
}
}
At the time of insertion it is working perfectly but when I select dynamically it is not working.
EDIT:
onItemSelect(item: any) {
this.selectedItems.push(item)
}
OnItemDeSelect(items: any) {
var id = items._id
this.selectedItems = this.selectedItems.filter((item) => item['_id'] !== id);
}
onDeSelectAll(items: any) {
this.selectedItems = items
}

in your component I cant see onItemSelect($event),OnItemDeSelect($event) and other multi select method bind to the event.
check this link :
https://www.npmjs.com/package/ng-multiselect-dropdown
add this in your component and try:
onItemSelect(item: any) {
console.log(item);
}

Not sure if it is even supposed to work. Please look at this issue: https://github.com/NileshPatel17/ng-multiselect-dropdown/issues/5.
Probably events get erased after reloading [data] (see my comment).

Related

I want to empty cells based on a value in another cell ag grid angular 7

I want to emty a cell based on the value in another cell. Both cells are custom rendered components
ie.
**comp1**
<div class="form-group input-group-sm">
<input
autocomplete="off"
class="form-control"
[(ngModel)]="value"
name="value"
type="number"
(ngModelChange)="updateMyData($event)"
[disabled]="disableDrpdwn()"
onkeypress="return (event.charCode >= 48 && event.charCode <= 57)"
onkeydown="return (event.keyCode!=13);"
(input)="onlyNumbers($event)"
/>
</div>
....
agInit(params: any): void {
this.params = params;
this.value = this.params.value;
}
disableDrpdwn() {
return this.params.data.amortizationPeriod === null || this.params.data.amortizationPeriod === 0;
}
updateMyData(data) {
this.params.data.amortizationPeriod = data;
if (this.params.data.amortizationPeriod === null || +this.params.data.amortizationPeriod === 0 ) {
this.params.data.amortizationMethod = null;
}
}
**comp2**
<div class="form-group input-group-sm dropdownSel">
<select #input [(ngModel)]="value" (ngModelChange)="updateMyData($event)" [disabled]= "disableDrpdwn()" class="form-control">
<option *ngFor="let item of dropdownnonInVal" [value]="item.name">{{ item.name}}</option>
</select>
</div>
....
agInit(params: any): void {
this.params = params;
this.value = this.params.value;
this.dropdownnonInVal = [{
name: 'Select',
value: ''
},
{
name: 'Yield Based',
value: 1
},
{
name: 'Price Based',
value: 2
}
];
}
updateMyData(data) {
this.params.data.amortizationMethod = data;
}
Here comp2 is dependent on comp1. So if I change the value of comp1's cell to 0, the value in the comp2's cell should be empty. i.e. the dropdown should get reset to blank on UI. How can I do it? Ngmodelchange is not doing any good. But the disable works properly. It the comp2 cell is disabled when the comp1 cell is 0 but the value is not getting blank. Need help.
I faced same issue in ag-grid. I guess there's no such functionality provided by AG Grid but obviously there's a workaround to it. You just need to empty the source (the cell you want to be emptied as in this.cellRenderer in image link) from which you're populating data in cellEditorParams (the cell you're changing values as in this.cellEditorParams in image link). Then put your logic in cellRenderer (the cell you want to be emptied as in this.cellRenderer in image link) as callback function.
image description here

knockout.js: how to make a dependent cascading dropdown unconditionally visible?

Getting started with knockout, I have been playing with the pattern found at http://knockoutjs.com/examples/cartEditor.html. I have cascading select menus where the second one's options depend on the state of the first -- no problem so far. But whatever I do, I haven't figured a way to change the out-of-the-box behavior whereby the second element is not visible -- not rendered, I would imagine -- until the first element has a true-ish value (except by taking out the optionsCaption and instead stuffing in an empty record at the top of my data -- more on that below.) The markup:
<div id="test" class="border">
<div class="form-row form-group">
<label class="col-form-label col-md-3 text-right pr-2">
language
</label>
<div class="col-md-9">
<select class="form-control" name="language"
data-bind="options: roster,
optionsText: 'language',
optionsCaption: '',
value: language">
</select>
</div>
</div>
<div class="form-row form-group">
<label class="col-form-label col-md-3 text-right pr-2">
interpreter
</label>
<div class="col-md-9" data-bind="with: language">
<select class="form-control" name="interpreter"
data-bind="options: interpreters,
optionsText : 'name',
optionsCaption: '',
value: $parent.interpreter"
</select>
</div>
</div>
</div>
Code:
function Thing() {
var self = this;
self.language = ko.observable();
self.interpreter = ko.observable();
self.language.subscribe(function() {
self.interpreter(undefined);
});
};
ko.applyBindings(new Thing());
my sample data:
roster = [
{ "language": "Spanish",
"interpreters": [
{"name" : "Paula"},
{"name" : "David"},
{"name" : "Humberto"},
{"name" : "Erika"},
{"name" : "Francisco"},
]
},
{"language":"Russian",
"interpreters":[{"name":"Yana"},{"name":"Boris"}]
},
{"language":"Foochow",
"interpreters":[{"name":"Lily"},{"name":"Patsy"}]
},
/* etc */
Now, I did figure out that I can hack around this and get the desired effect by putting
{ "language":"", "interpreters":[] }
at the front of my roster data structure, and that's what I guess I will do unless one of you cognoscenti can show me the more elegant way that I am overlooking.
After using both Knockout and Vuejs, I found Vuejs much easier to work with. Knockout is a bit out dated and no longer supported by any one or group.
Having said that, here is how I addressed your issue. The comments here refer to the link you provided not your code so I could build my own test case.
My working sample is at http://jsbin.com/gediwal/edit?js,console,output
I removed the optionsCaption from both select boxes.
Added the following item to the data (note that this has to be the first item in the arry):
{"products":{"name":"Waiting", "price":0}, "name":"Select..."},
I added the disable:isDisabled to the second selectbox cause I want it to be disabled when nothing is selected in the first selectbox.
added self.isDisabled = ko.observable(true); to the cartline model
altered the subscription to check the new value. If it is the select option the second one gets lock.
function formatCurrency(value) {
return "$" + value.toFixed(2);
}
var CartLine = function() {
var self = this;
// added this to enable/disable second select
self.isDisabled = ko.observable(true);
self.category = ko.observable();
self.product = ko.observable();
self.quantity = ko.observable(1);
self.subtotal = ko.computed(function() {
return self.product() ? self.product().price * parseInt("0" + self.quantity(), 10) : 0;
});
// Whenever the category changes, reset the product selection
// added the val argument. Its the new value whenever category lchanges.
self.category.subscribe(function(val) {
self.product(undefined);
// check to see if it should be disabled or not.
self.isDisabled("Select..." == val.name);
});
};
var Cart = function() {
// Stores an array of lines, and from these, can work out the grandTotal
var self = this;
self.lines = ko.observableArray([new CartLine()]); // Put one line in by default
self.grandTotal = ko.computed(function() {
var total = 0;
$.each(self.lines(), function() { total += this.subtotal() })
return total;
});
// Operations
self.addLine = function() { self.lines.push(new CartLine()) };
self.removeLine = function(line) { self.lines.remove(line) };
self.save = function() {
var dataToSave = $.map(self.lines(), function(line) {
return line.product() ? {
productName: line.product().name,
quantity: line.quantity()
} : undefined
});
alert("Could now send this to server: " + JSON.stringify(dataToSave));
};
};

JQuery Mobile filterable listview with multiple filters

I have a JQM 1.4.2 filterable listview which contain entries in different languages.
I would like to search only within items code, not the whole description, whereby i set the data-filtertext for list items to the item code, e.g. "Apple" or "Banana".
This works ok but now i need an additional language filter, e.g. "EN", "DE", and so on:
...
<li data-filtertext="Apple language_en">
<h2>Title</h2>
<p>Red fruit</p>
<p class="ui-li-aside"><strong>EN</strong></p>
</li>
...
...
<li data-filtertext="Banana language_de">
<h2>Titel</h2>
<p>Beschreibung</p>
<p class="ui-li-aside"><strong>DE</strong></p>
</li>
...
This is my data input:
<form class="ui-filterable">
<div class="ui-grid-a">
<div class="ui-block-a">
<input id="descriptions-input" data-type="search" placeholder="Search..." />
</div>
<div class="ui-block-b">
<fieldset data-role="controlgroup" data-type="horizontal">
<input name="lang-en" id="lang-en" type="checkbox" data-mini="true">
<label for="lang-en">EN</label>
<input name="lang-de" id="lang-de" type="checkbox" data-mini="true">
<label for="lang-de">DE</label>
<input name="lang-fr" id="lang-fr" type="checkbox" data-mini="true">
<label for="lang-fr">FR</label>
</fieldset>
</div>
</div>
</form>
What i try to do now, is that when a checkbox is selected, only the list items belonging to that language are visible.
How can i set this additional filter to my filterable jQuery Mobile listview?
Plunker: http://plnkr.co/edit/TV6rcatzdvaIvQzWBdoI?p=preview
EDIT:
This is the final solution, thanks to EZANKER: https://jsfiddle.net/m64kg5fw/4/
The filterable widget as a filterCallback property: http://api.jquerymobile.com/filterable/#option-filterCallback
You can use this to write a function that checks both the text and which language checkboxes are checked.
$(document).on("pagecreate", "#list-descriptions", function () {
$("#descriptions-list").filterable('option', 'filterCallback', checkedOrMatch);
$("#searchLangs input").on("change", function(){
$("#descriptions-list").filterable("refresh");
});
});
function checkedOrMatch(idx, searchValue) {
var ret = false;
var en = $("#lang-en").is(':checked');
var de = $("#lang-de").is(':checked');
var fr = $("#lang-fr").is(':checked');
var ignoreLang = false;
if (!en && !de && !fr) {
ignoreLang = true;
}
if (searchValue && searchValue.length > 0) {
searchValue = searchValue.toLowerCase();
var filttext = $(this).data("filtertext") || '';
filttext = filttext.toLowerCase();
if (filttext.indexOf(searchValue) < 0) {
ret = true; //filter this one out
} else if (!ignoreLang) {
//found filter text now check language
if ( (filttext.indexOf("language_en") > 0 && !en) || (filttext.indexOf("language_de") > 0 && !de) || (filttext.indexOf("language_fr") > 0 && !fr) ) {
ret = true; //filter this one out
}
}
}
return ret;
}
Updated DEMO
The checkedOrMatch functions runs for each item in the list. It first tests if the entered search text is found in the filter text. If it is, it then sees which language buttons are checked and tests the item for that language. I also added code to re-trigger the filter if the user selects language buttons after typing the search criteria.
NOTE: if the user types in "lang" you might not get what you want... In that case you could move the language designation out of the filter text and into a separate data-attribute.

UI saying my observableArray().length == 0 one minute, then == 1 the next?

I am using knockout.js. I declare 2 model objects:
1)
var model =
{
products: ko.observableArray([])
}
2)
var customerModel =
{
cart: ko.observableArray([]),
filteredProducts: ko.observableArray([]),
currentView: ko.observable("list")
}
when the document is ready:
$(document).ready
(
function () {
getProducts();
}
);
it calls getProducts which sets the model.products observable array to have a single object:
var getProducts = function () {
model.products.removeAll();
model.products.push
(
{
Id: 1,
Name: "Product 1",
Description: "A nice product",
Price: 666.66,
Category: "Category 1"
}
)
}
i have a view that renders an ASP.NET partial view. the default customerModel.currentView is 'list' (as seen from the model object i declared):
<div data-bind="visible: customerModel.currentView() == 'list'">
#Html.Partial("ProductList")
</div>
in the partial view (ProductList.cshtml) is the following code:
<div data-bind="foreach: model.products()">
<span data-bind="text: $data.Description"></span>
<button data-bind="click: addToCart">Add to Cart</button>
</div>
clicking on the button invokes the addToCart function which adds a product to the cart and sets the view:
var addToCart = function (product) {
var cart = customerModel.cart;
cart().push
(
{
product: product,
count: 1
}
);
setView('cart');
}
setView is like this:
var setView = function (view) {
customerModel.currentView(view);
}
when set to 'cart', the following code renders a partial view:
<div data-bind="visible: customerModel.currentView() == 'cart'">
#Html.Partial("ProductCart")
</div>
now HERE is the kicker. ProductCart.cshtml looks like this:
<script>
var testCart = function () {
alert("There is " + customerModel.cart().length + " item incustomerModel.cart()");
}
</script>
<div data-bind="if: customerModel.cart().length == 0">There are no items in customerModel.cart( </div>
<button data-bind="click: testCart">Test Cart</button>
so guess what? the div that says "There are no items in customerModel" shows up because customerModel.cart().length == 0, however when i click the button the alert tells me that customerModel.cart().length is equal to 1.
It seems that you need to change cart().push to cart.push, as you are doing with model.products.
Thats how observableArrays work. See documentation.
When you call cart(), it returns a new array, with the values inside the observable. You are pushing your new value to that array, which is being lost in limbo.
You need to call the push method through the ko.observableArray API, this way it will notify all subscribers for that change, and the new value will be added to the observableArray.

MVC Force jQuery validation on group of elements

My form I am designing with MVC 4 has mutiple DIVS with many elements in each one. My objective is to open/close DIVS as the user completes the fields. However, I want to use the unobtrusive validation on each DIV, rather than the whole form. Is that possible without checking each element individually? Maybe using a DIV ID or something? I don't want to build this massive function to check each and every element in each DIV just so the user can move to the next DIV.
I am trying this and it is not working:
var elems = [];
var valid = true;
("#Contact").find('.text_input').each(function() {
elems.push(this.id);
}
for (var i = 0; i<= elems.length; i++) {
if ($("#" + elems[i]) != undefined) {
$("#form1").validate().element("#" + elems[i]))
if ($("#" + elems[i]).valid()) {
}
else {
valid = false;
}
}
}
but I keep getting an undefined error. The elements in the DIV that have the class text_input are the ones with validation required.
You can validate individual controls using Validator.element(element) - see documentation here, so you could use the following approach (you haven't posted the views html so can't write the actual code for you)
In the Next button click event
Select all the the controls within the
associated div - e.g. var controls = $(this).closest('div').find('input, textarea, select');
In an $.each loop, call $("form").validate().element($(this));
If necessary, test if valid with $(this).valid();
If everything is valid, hide the current div and display the next
Edit (example added)
View
<div class="section">
<h2>Section 1</h2>
.... // Your inputs and validation
#Html.LabelFor(m => m.SomeProperty)
#Html.TextBoxFor(m => m.SomeProperty)
#Html.ValidationMessageFor(m => m.SomeProperty)
<div class="error"></div>
<button type="button" class="next">Next</button>
</div>
<div class="section">
<h2>Section 2</h2>
.... // Your inputs and validation
<div class="error"></div>
<button type="button" class="next">Next</button>
</div>
<div class="section">
<h2>Section 3</h2>
.... // Your inputs and validation
<div class="error"></div>
<button type="submit" class="next">Submit</button> // submit button for last section
</div>
CSS
.section:not(:first-of-type) {
display:none;
}
Script
$('button').click(function () {
var container = $(this).closest('.section');
var isValid = true;
$.each(container.find('input'), function () {
$('form').validate().element($(this));
if (!$(this).valid()) {
isValid = false;
return false;
}
});
if (isValid) {
container.next('.section').show().find('input').first().focus();
container.hide();
} else {
container.find('.error').text('please complete');
}
});

Resources