Hie.I have a basic angular2 forms where i have nested objects.What i am trying to make is that i want to get only those fields which are dirty.I am facing problem to get the values of deeply nested objects...This is my demo http://plnkr.co/edit/gzT4mVWglHrFziRayHtK?p=preview ,here changes done in Contacts fields are coming in main Object...
{
"addressinfo": {
"Line1": "",
"Line2": ""
},
"firstname": "",
"lastname": "",
"Contacts": {
"Phone1": {
"Type": "",
"Number": ""
}
}
}
If I change Number Field and submit the form then I am getting the response object in this way...
{
"Contacts": {},
"Phone1": {
"Number": ""
}
}
Since Number field has been changed i want the output to be in this way
{
"Contacts": {
"Phone1": {
"Number": ""
}
},
}
Somebody help me to get only the changed data in the right object format...Thanks
Have you tried to step through your code in a debug session (by using the debugger statement for example)? When it is checking your Contacts control group it pushes this name as new object onto the ResultObject and starts executing recursivelyIterateProperties(jsonObject,ResultObject,activeProperty) again, with the following parameters:
jsonObject = {Phone1: ControlGroup},
ResultObject = {Contacts: {}},
activeProperty = 'Contacts'
The problem is that Phone1 is again a control group and therefore your === 'object' code is executed again, pushing a new Phone1 object directly onto the ResultObject. In other words, your code doesn't handle nested control groups very well.
I have taken the liberty to rewrite your code a bit into a working example: Plunker.
For clarity the iteration over the initial control groups has been split from the collection of the values. We first iterate over all controls:
iterateOverControls(controls, resultObject): any {
var resultObject = {};
// Iterate over controls and controlgroups
for ( var control in controls ) {
var result = {}
// Only look into dirty controls
if ( controls.hasOwnProperty(control) && !controls[control].pristine ) {
result[control] = this.retrieveValuesForControl(controls[control]);
// Once we have collected the changes, add them to the result object
for ( var key in result ) {
if ( result.hasOwnProperty(key) ) {
resultObject[key] = result[key];
}
}
}
}
return resultObject;
}
For each control that we encounter, we try to collect its values by calling retrieveValuesForControl. This method expects the control we are currently looking into as a parameter.
retrieveValuesForControl(control): any {
// Only check dirty objects
if ( control.pristine ) {
return;
}
var values;
if ( typeof(control.value) === 'object' && control.controls ) {
// The current control is a control group, so we need to look deeper
values = {};
for ( var item in control.controls ) {
// We retrieve values for this control again (recursively)
values[item] = this.retrieveValuesForControl(control.controls[item]);
}
} else if ( !control.pristine) {
// We have a control, so copy the value
values = control.value;
}
// Return our collected values (either a plain value or object of values)
return values;
}
In this method we first check if the control we are looking at is dirty. If it is pristine, we return directly. Next we check if we are looking at a control group or a control.
In case of a control group: we want to look into the control group again by calling iterateOverControls for each and every control that the control group contains. The results of these calls are collected, put into one object and returned when we are done.
In case of a control: we can collect the value an return it.
I feel like you are not able to find them properly.
console.log(this.myForm.controls.Contacts.controls.Phone1.controls);
This is the exact way where you can find Number and Type. I don't see any problem in your plunker.
You can also subscribe to
this.myForm.valueChanges.subscribe(...)
and collect changed values this way.
Related
I’m checking whether there is a placeholder present in the “all” string within alertDetails object so my question is I need to access email,sms,fax property that appears dynamically based on user’s input (the code is a part of an alert box in which an user can choose to send alert via different delivery methods) so I saved all the possible delivery methods in an array and tried like below;
Const delmethod=[“email”,”sms”,”fax”]
for(let i=0;i<delmethod.length;i++)
{
Console.log(alertDetails &&
alertDetails.alertMessage &&
alertDetails.alertMessage[${lang}] &&
alertDetails.alertMessage[${lang}].all
? alertDetails.alertMessage[${lang}][‘${delmethod(i)}’].includes('placeholder')
: false;
}
P.S:the property “all” is fixed it’s just the email fax will be changing based on user’s input, to sum it up I want to return true if “placeholder” exists in any of the strings(all,email,fax,sms) the method I tried just prints the del method array, I’d appreciate any help thanks!
There are multiple issues with your code. You cannot just use ${lang}. You must surround your string with backticks (`) if you want to use template literals.
To access properties of an object you need a a key i.e. a string which you already have so in this case template literals are not required at all.
When you access an array by index you need to use [] not () so use delmethod[i] instead of delmethod(i). Additionally make sure an property exists on an JavaScript object.
const delmethod = ["email", "sms", "fax"];
const alertDetails = {
alertMessage: {
en: {
all: "emailsfsdfsdfsd",
fax: "placeholder",
sms: "sdkjföskjfsödkj"
},
},
};
const lang = "en";
for (let i = 0; i < delmethod.length; i++) {
if (
alertDetails &&
alertDetails.alertMessage &&
// use backticks ` when trying to use template literals
alertDetails.alertMessage[`${lang}`] &&
// there is actually no need for template literals here
alertDetails.alertMessage[lang].all &&
// you need to make sure "sms" or "fax" or "email" key actually exist on the object
alertDetails.alertMessage[lang][delmethod[i]] &&
alertDetails.alertMessage[lang][delmethod[i]].includes("placeholder")
) {
console.log(
`alertDetails.alertMessage[${lang}][${delmethod[i]}] does have a placeholder`
);
console.log(true);
} else {
console.log(
`alertDetails.alertMessage[${lang}] does NOT have property ${delmethod[i]} or does NOT have a placeholder`
);
console.log(false);
}
}
I want to make a list of checkboxes on a UI that user's can use to toggle and filter a set of data results. The checkboxes can be cumulative so I store them as a string array for now. My code looks something like this.
export interface IMyObjectFromAPI {
status: {
id: number,
description: string,
location: string,
name: string,
imageUrl: string
}
}
var filteredByTerms: string[] = [];
var resultsFromAPI: IMyObjectFromAPI [] = [];
var filteredDataResults: IMyObjectFromAPI[] = [];
I save the return results from the api call into the resultsFromAPI array.
On the UI, I have a group of checkboxes based on countries that is populated with a loop through a countries array. On select of a checkbox, I fire off the following code. Again, the goal here is to add multiple things to the array of terms to filter by (so I want to filter by location + name).
filterDataResults(term: string) {
var indexOfTerm = this.filteredByTerms.indexOf(term);
// if the term is not in an array of terms to filter by, add it
if (indexOfTerm === -1) {
this.filteredByTerms.push(term);
this.filteredDataResults = this.resultsFromAPI.filter(x => x.location ===
this.filteredByTerms.includes(term));
}
else {
this.filteredByTerms.splice(indexOfTerm, 1);
this.filteredDataResults = this.resultsFromAPI.filter(x => x.location ===
this.filteredByTerms.includes(term));
}
}
I don't know if I'm explaining this correctly but I've attached a picture to help. A series of checkboxes on the left, a data set on the right, and the checkboxes can be cumulative (so in the image example, if I select ITContractor and Clinical Psychology, the filter function would look for something in the results returned from the API which statifies both conditions.
It seems like some HOFs and map of filters might help you organize your user determined logic/filtering.
const filters = {
lastHourFilter: (result) => result.postedDate > Date.now() - ms('1 hour'),
last24HoursFilter: (result) => result.postedDate > Date.now() - ms('24 hours'),
...
itContractorFilter: generateSpecialismFilter('IT Contractor'),
clinicalPsychologyFilter: generateSpecialismFilter('Clinical Psychology'),
...
fullTimeFilter: generateJobTypeFilter('Full Time'),
temporaryFilter: generateJobTypeFilter('Temporary')
}
Then you inspect the check boxes and determine which filters you should apply to the results. Something like:
function applyFilters(results) {
Object.keys(filters).forEach((key) => {
if (checkboxes[key].checked) results =
results.filter(filters[key]);
});
return results;
}
Here checkboxes is a map of checkboxes in the DOM indexed by the same keys as your filters.
I built a custom component that filters an array of objects. The filter uses buttons, sets from active to non-active and allows more than one option on/off at the same time.
StackBlitz of my attempt - https://stackblitz.com/edit/timeline-angular-7-ut6fxu
In my demo you will see 3 buttons/options of north, south and east. By clicking on one you make it active and the result should include or exclude a matching "location" either north, south and east.
I have created my methods and structure to do the filtering, I'm struggling with the final piece of logic.
So far I have created a method to create an array of filtered locations depending on what the user clicks from the 3 buttons.
Next this passes to my "filter array" that gets the logic that should compare this filtered array against the original to bring back the array of results that are still remaining.
Its not quite working and not sure why - I originally got this piece of functionality working by using a pipe, but fore reasons do not want to go in that direction.
//the action
toggle(location) {
let indexLocation = this.filteredLocations.indexOf(location);
if (indexLocation >= 0) {
this.filteredLocations = this.filteredLocations.filter(
i => i !== location
);
} else {
this.filteredLocations.push({ location });
}
this.filterTimeLine();
}
// the filter
filterTimeLine() {
this.filteredTimeline = this.timeLine.filter(x =>
this.contactMethodFilter(x)
);
}
//the logic
private contactMethodFilter(entry) {
const myArrayFiltered = this.timeLine.filter(el => {
return this.filteredLocations.some(f => {
return f.location === el.location;
});
});
}
https://stackblitz.com/edit/timeline-angular-7-ut6fxu
Sorry for my expression but u have a disaster in your code. jajaja!. maybe u lost that what u need but the logic in your functions in so wrong. comparing string with objects. filter a array that filter the same array inside... soo u need make a few changes.
One:
this.filteredLocations.push({location});
Your are pushing object. u need push only the string.
this.filteredLocations.push(location);
Two:
filterTimeLine() {
this.filteredTimeline = this.timeLine.filter(x =>
this.contactMethodFilter(x)
);
}
in this function you filter the timeLine array. and inside of contactMethodFilter you call filter method to timeLine again....
See a functional solution:
https://stackblitz.com/edit/timeline-angular-7-rg7k3j
private contactMethodFilter(entry) {
const myArrayFiltered = this.timeLine.filter(el => {
return this.filteredLocations.some(f => {
return f.location === el.location;
});
});
}
This function is not returning any value and is passed to the .filter
Consider returning a boolean based on your logic. Currently the filter gets undefined(falsy) and everything would be filtered out
I am new in JavaScript, And I am trying to map my controller's buttons and leds for mixxx application. Is that an object, an array? var is missing.
BehringerCMDMM1.leds = [
// Master
{ "shiftButton" : 0x12 },
// Deck 1
{ "sync" : 0x30 },
// Deck 2
{ "sync" : 0x33 }
];
I have an error here,
BehringerCMDMM1.shiftButton = function (channel, control, value, status, group) {
// Note that there is no 'if (value)' here so this executes both when the shift button is pressed and when it is released.
// Therefore, BehringerCMDMM1.shift will only be true while the shift button is held down
var deck = BehringerCMDMM1.groupToDeck(group);
BehringerCMDMM1.shift = !BehringerCMDMM1.shift // '!' inverts the value of a boolean (true/false) variable
BehringerCMDMM1.setLED(BehringerCMDMM1.leds[deck]["shiftButton"], BehringerCMDMM1.shift);
}
about "shiftButton" as undefined.
also I have this function
BehringerCMDMM1.setLED = function(value, status) {
status = status ? 0x7F : 0x00;
midi.sendShortMsg(0x94, value, status);
}
This is from a javascript file I found on the internet created for a different controller. So, I am trying things to understand how can I configure mine.
BehringerCMDMM1.leds is an array of objects. Within that array, the element at index 0 is an object that has a shiftButton property. Thus, the only way to get the 0x12 value in your example is to do this:
BehringerCMDMM1.leds[0]['shiftButton']
So when this code executes...
var deck = BehringerCMDMM1.groupToDeck(group);
...the value of deck is probably something other than 0, and you're accessing one of the sync objects in the BehringerCMDMM1.leds array. For example, if the value of deck was 1, then this...
BehringerCMDMM1.leds[deck]['shiftButton']
...will be undefined because you're effectively doing this:
BehringerCMDMM1.leds[1]['shiftButton']
Ok,
I am new in JavaScript, And I am trying to map my controller's buttons and leds for mixxx application. Is that an object, an array?
You have a array of objects.
var is missing.
You should test what is inside yout deck variable. Try this:
console.log(deck);
if (deck in BehringerCMDMM1.leds) {
BehringerCMDMM1.setLED(BehringerCMDMM1.leds[deck]["shiftButton"], BehringerCMDMM1.shift);
} else {
console.log("Index: "+deck+" doesn't exist");
}
I have an array of objects that presents as follows:
0: Object
ConsolidatedItem_catalogId: "080808"
ConsolidatedItem_catalogItem: "undefined"
ConsolidatedItem_cost: "0"
ConsolidatedItem_description: "Test Catalog Item"
ConsolidatedItem_imageFile: "27617647008728.jpg"
ConsolidatedItem_itemNumber: "1234"
ConsolidatedItem_quantity: "1"
ConsolidatedItem_source: "CAT"
ConsolidatedItem_status: "02"
ConsolidatedItem_umCode: "EA"
1: Object
ConsolidatedItem_catalogId: ""
ConsolidatedItem_catalogItem: "undefined"
ConsolidatedItem_cost: "0"
ConsolidatedItem_description: "ALARM,SHUTDOWN SYSTEM,AXIOM,XP3, 0-1500 PSIG, HIGH AND LOW PRES Testing"
ConsolidatedItem_imageFile: ""
ConsolidatedItem_itemNumber: "10008"
ConsolidatedItem_quantity: "1"
ConsolidatedItem_source: "INV"
ConsolidatedItem_status: "02"
ConsolidatedItem_umCode: "EA"
I'm trying to update and remove an object if it's added again, or update the object. Preferably update the object with the new value. My code is as follows:
var result = $.grep(finalObject, function(e) {
return e.ConsolidatedItem_itemNumber == o.ConsolidatedItem_itemNumber;
});
console.log(result);
if (result.length == 0) {
finalObject.push(o);
shoppingCounter = finalObject.length;
$('#numberShoppedItems').text(shoppingCounter);
console.log(finalObject);
} else if (result.length == 1) {
finalObject.filter(function(x){
result = x;
console.log(result);
return x == result.ConsolidatedItem_itemNumber;
});
} else {
alert('Multiples Found');
}
}
I've tried multiple ways of getting the exact object and manipulating the data, however they've all failed. I would prefer to update the object, say if CatalogItem_itemNumber held the same value, if the CatalogItem_quantity was different - add the CatalogItem_quantity values together and update the array of objects.
I don't need an exact answer, a nudge in the right direction would do wonders though. I've looked at several of the related questions over the past couple of hours but none of them seem to address the issue. If you know of a question that has an answer, feel free to just link that as well. I may have missed it.
No Underscore.js please
When you find the matching record, you may update it by using $.extend
$.extend(result[0], o)
This will update the object in finalObject array in-place.
Alternatively, if you want to use the filter, you will need to insert the new object in the array.
finalObject = finalObject.filter(function(x) {
return x !== result[0];
});
finalObject.push(o)
Here we are allowing all the records that are not not equal to result to be returned in the resultant array that is received in finalObject. In next line, we are adding the new record.
Solved in the following manner:
1.) Verify object is not empty.
2.) Use .some() on object to iterate through it.
3.) Check if the finalObject, which is now e, has a match for the key in my temporary object I assemble, o.
4.) Update the values that need updating and return true;
Note: Originally I was going to remove the object by its index and replace it with a new object. This too can work by using .splice() and getting the index of the current object in that array you're in.
Here is the updating version:
if (o.ConsolidatedItem_quantity != '') {
var result = $.grep(finalObject, function(e) {
return e.ConsolidatedItem_itemNumber == o.ConsolidatedItem_itemNumber;
});
if (result.length == 0) {...}
else {
finalObject.some(function (e) {
if(e.ConsolidatedItem_itemNumber == o.ConsolidatedItem_itemNumber){
var a;
a = +e.ConsolidatedItem_quantity + +o.ConsolidatedItem_quantity;
e.ConsolidatedItem_quantity = a.toString();
document.getElementById(o.ConsolidatedItem_itemNumber).value=a;
return true;
};
});
}
}