ObservableArray child observable change monitoring - javascript

Consider this jsfiddle.
I can't think of a way to ensure that if row one in the above example has already been selected in the dropdown that the next row would be prevented from selecting the same value.
I think that my problem here is that when the dropdown click event fires, the subscriber does not monitor this change when the child value has changed. Anyone able to assist?
viewModel.actualMetrics.subscribe(function(newValue) {
if (newValue) {
$.each(viewModel.actualMetrics(), function(n, item) {
if (item.MetricTypeId() == newValue.MetricTypeId)
alert("already selected this Metric");
});
}

Here is a basic sample of one way to do what you want: http://jsfiddle.net/rniemeyer/3cpUp/
Here is your sample with it: http://jsfiddle.net/rniemeyer/8bQmq/
The basic idea is that you have your list of choices, then you create a dependentObservable that is an index of the currently used choices. This saves some looping through the current choices when building each rows options. This index could be an object or an array. I used an object, but you could use an array as well with the id as the index.
Then, on each item, you could have a dependentObservable to store the filtered choices for that item. However, I used a function instead, because it does not seem like a property that is really important to the view model and bindings are implemented using dependentObservables, so you get the same effect without having the choices show up when you send it toJSON. The function loops through all of the choices and includes only the choices that do not appear on another line by checking its own value and the index.

Related

JS <select> listbox not working on click/change

what I need to do is to gather some data online via fetch and use the data to give the user infos and such (that I can do). In some cases, the fetch can return multiple results (an array of data), so I decided to create a element in the page to list all the names of the elements in the array (each element in the array is a sub-array with various infos, also a "name", which would be a location name).
I'm working on Chrome. All works, I store the data and this way I created another function to (theoretically) give the user the infos about the selected option in the listbox. If I call the function directly it works fine, meaning it returns all the infos it should. What actually doesn't work is the fact that this function returning infos should trigger on click/selecting any option from the list and it doesn't work. I don't get any error messages, it just does nothing.
What you see in this image is what happens when you click "filter" (it actually filters world locations detected with name similar to "Milano"), the user gets infos in the page and what you see in the right log side in the red square is returning the content of that array I mentioned (it contains data, so it's working), the index selected in the list (the last, so it's 5) and the coordinates of such selected location.
This happens just after the creation of the options because I directly call the function (returning data about the selected option), but if I use manually the list it just does nothing (as you see in the list, there's nothing logged after those coordinates).
I tried to create the options like this:
function createOption(text){
let listOption = new Option(text, text, true, true);
return listOption;
}
What I do directly to create the options in the list is a "for" loop for each element i in the array:
document.getElementById("keyword-results").append(createOption(data.data[i].station.name));
I also tried appendChild instead of append. As I said, this works, but the manual use of the list doesn't. What I declared is:
document.getElementById("keyword-results").addEventListener("onchange", selection());
being "selection()" the function returning the data.
function selection(){
let index = document.getElementById("keyword-results").selectedIndex;
console.log(index);
if (index > -1){
let currentResult = results.data[index];
let aqi = currentResult.aqi;
console.log(aqi);
document.getElementById("answer").innerHTML += `The estimated AQI [...]`;
let far = distance(currentResult.station.geo[0], currentResult.station.geo[1]);
if (far != null || far != undefined) {
document.getElementById("answer").innerHTML += `The estimated distance [...]`;
}
}
}
I also tried "change", "onclick" and "click" as methods to trigger the function but none of them works. Do you have any suggestions? I can't find anything useful here on stackoverflow nor on the web. If you want to check the whole code, this is my GitHub repository https://github.com/leorob88/pollution-forecast-API
document.getElementById("keyword-results").addEventListener("onchange", selection());
addEventListener expects a function as a second parameter, selection() is not a function but selection is.
When you use addEventListener, there is no such event named onchange its actually change
so it becomes:
document.getElementById("keyword-results").addEventListener("change", selection);
Reference.

Issue with record.setFieldValues() in SuiteScript Emptying Field Values

Ok, so I have a user event script attached to a custom record. One of the fields on this custom record is a select field for item records. In the user event script, it's getting the value of this field, checking the item options on the selected item. As it runs through the values, it checks to see if it's missing certain values and adds them if necessary. The problem I'm having is that it's ultimately setting the item options field to blank. I've tried both with loading the record, setting the values, then saving, and also by trying to just set a single value with nlapiSubmitField(). The outcome is the same both ways. Here's a quick rundown of the code:
var itemId = customRec.getFieldValue("custrec_item_field");
var itemRec = nlapiLoadRecord("noninventoryitem", itemId, { recordmode : "dynamic" });
var optArray = [ "CUSTCOL_OPT1" , "CUSTCOL_OPT2" , "CUSTCOL_OPT3" , "CUSTCOL_OPT4" ];
itemRec.setFieldValues("itemoptions", optArray);
nlapiSubmitRecord(itemRec, true, true);
Now, a few months back I was certain this was working correctly, and if I apply similar login to a user event BeforeSubmit function when the item record saves, everything works as intended. I'm sure I could get this to work by triggering an edit on the item record within a Suitelet called from the original user event, but that seems ridiculous. There are no errors encountered unless I pass in the item option values through in lower case. Am I missing something? Or am I just going to have to find a way to trigger this outside of this user event function?
There was a flaw somewhere else that was clearing the options out because it mistakenly thought the selected value had changed.

Clone sapUi5 json model and stop binding

I have seen a similar question, but in my case it doesn't work.
I have a JSON model, called data, which corresponds to a SAPUi5 form with comboboxes. I want to copy the state of the model the first time I open my application and keep it like that. After that I want to use it to reset my form and bring the comboboxes back to their default values.
When I first start my application:
this.getView().setModel(new JSONModel(data)); //create the original model
//copy the original model (copyModel is global variable
copyModel = $.extend({}, data);
Until here everything is fine. The two models are exactly the same. After that I have a button and a reset Function:
resetP: function(){
this.getView().setModel(new JSONModel(copyModel));
console.log(copyModel);
}
The first time I select something in the comboboxes and click the reset button and run the reset function, the copymodel is the right one. Same with the original data model. When I change again the selected value of the combobx, the copyModel, starts taking the selected value. Somehow it's overwritten. I don't know what I am doing wrong. Are there any suggestions? I have also tried to use JSON.strignify instead of extend.
JSON models be default have two way binding. So when you are triggering events like selectionChange on the ComboBox, because of two way binding, the set data to the model keeps getting updated. Also Javascript has objects by reference, so it is the original copyModel object that gets updated.
You can prevent this by setting a copy of the copyModel to the JSON model.
Another thing I would like to mention is that do not keep setting the model again and again.
You can just update the data that is set to the model and update the model.
This can be done in 2 ways.
a.
resetP: function(){
this.getView().getModel().setData(copyModel);
console.log(copyModel);
}
b. You could also update the required property and do a
this.getView().getModel().updateBindings();
We use jQuery.extend(true, {}, object_to_copy); in this way to create a "deep copy" from the object we want an independed copy from.

Remove all elements within a ng-repeat in Angular

I'm working with Angular and part of my page utilizes ng-repeat to display some bug tracker tickets. As part of the site, I also want to provide the ability to search tickets. I'm able to get that part working as I want, and if I'm just appending new tickets they show up fine.
However I would like to be able to, if a user searches, delete all of the currently visible ticket divs and replace them with the search results.
My initial thinking, since I have the ng-repeat set as item in tickets track by item.id, was to just set $scope.tickets equal to the new data. However, this didn't cause Angular to update the DOM.
So, I tried setting $scope.tickets equal to an empty array and then setting it equal to the new data:
$scope.$apply(function() {
$scope.tickets = [];
$scope.tickets = data;
});
Still no update to the DOM, even though console.log($scope.tickets) shows the correct objects.
I'm aware of the method of
$scope.$apply(function() {
array.splice(index, 1);
});
to remove individual elements, but I'm not sure how I would apply that removing all of the elements.
I'll try and get a Plunkr or JSBin added to the Q soon.
What would be the proper way for me to make Angular replace all of the current elements with the new elements created from the data?
try setting array.length = 0
this deletes all elements, while not removing the reference to the array, which actually seems to be the problem in your case.
but another way would be to have a additional data bag.
for example have $scope.data.tickets then you can reasign tickets as usual. important thing is, you have to reference your items using item in data.tickets
Did you test $watch?
$scope.$watch('tickets', function() {
// update data HERE
});

Changing Observable Property of One Object Changes Property of All In Collection

I have a collection of objects in my view model. I'm experiencing an issue when binding a value to select control. The value is a JS object and not a primitive type. When I have more than one object in the bound collection and change the select control, all of the other object's values update to the newly selected one. It's like all of the values are bound to the same instance inside the foreach binding. The error only seems to happen when new rows are inserted, not when simply editing existing ones.
I have striped out a lot of the complexities and have an example showing the issue on JSFiddle.
http://jsfiddle.net/zero21xxx/5vgDy/
Steps to see the Error
Select Settle Type from the drop down of row 1
Select "Two" from the new drop down to the right.
Select Settle Type from the drop down of row 2
Both row 1 and row 2 will now both be set to "One" in the select box.
I would expect that a change in one row would not effect any of the other rows.
It's all a bit complicated how you have it setup, however, I think the problem is, that your ids are not what you expect,
function getValues(tabId) {
console.log("tabId " + tabId);
if (lookUp[tabId]) {
if I add that to your code, it show's the same tabId, which means you are dealing with the same objects by the looks of it.
if I change getValues so each time it does
function getValues(tabId) {
console.log("tabId " + tabId);
return [new DatabaseField(nextId(), "Name", "Attorney Name", DataType.STRING.id),
new DatabaseField(nextId(),
"Type", "Settle Type", DataType.DROPDOWN.id)];
}
also I changed all the observables with [] to observable arrays...
then it seems to work. fiddle... http://jsfiddle.net/keith_nicholas/wmxJX/
Each time that you choose a different selectedDatabaseField it rebuilds the availableOptions.options. Each of the rows are bound against these same options as choices. When the options are rebuilt, then each row's selected value is no longer a valid choice.
Even if the object looks exactly the same it is not equal unless it is a reference to the same object.
So, since the options have changed and the currently selected value is no longer valid, the value binding will assign the first option as the value (unless you have an optionsCaption specified).
So, you probably don't want to rebuild the options, if they are already built or you would want separate options for each row rather than binding against the same database field object.

Categories