Managing nested dependent data in Knockoutjs - javascript

I have a JSON object which contains models array. Each model contain params array and each param contain values. values should displayed on page as radiobuttons or selects and user can choose it. I need to build HTML so that if user chooses the value then variable selectedValues keeps object like this {param_id: value_id, another_param_id: another_value_id} e.t.c. This variable should show what values for which parameters selected by the user. The problem is i don't know how many params and how many value will come - it's fully dynamic JSON, generated by server.
Demo fiddle
http://jsfiddle.net/z68tx53c/1

If you are using selectedValues()[1] when selectedValues() is null (which you are, before it's populated), you will get this error: Cannot read property '1' of undefined . Wrap the html which uses selectedValues in a with or if binding, so that the containing nodes are only there when selectedValues is non null.

Related

Preload already selected items on vue multiple-autocomplete

Let's say I have a vue-component that is able to store multiple options from a api-fetching-based autocomplete.
Looks a lot like this one but the model (which I think represents the selected entries) is an array and the v-autocomplete has the multiple option. https://vuetifyjs.com/en/components/autocompletes/#api-search
here is the codepen I edited https://codepen.io/cesarbonadio/pen/bGYLMGa?editors=1010
The problem is that I can't get it work when I try to preload already persisted data to that component.
what I currently do:
I pass the data through a prop, then I map it and assign it to the model property of the component.
The problem is that at the first instance, the selected options doesn't show up, only when I do the search inside the autocomplete, which causes the search-string to update.
if I initialize the search string as search: "", then it works, it does a search with the search-string empty, fetching all the elements that matches with "" (in other words, all of them). This is bad performance and it is not ideal because I have like 8 or 9 autocompletes inside the same parent-component.
What I can do to show up the selected options without forcing the empty search?

How to delete an attribute when sending a partial object update to Algolia?

I need to use partialUpdateObject from the Algolia Javascript SDK to delete an attribute from an object that is already in the index.
My scenario is that I have a description field on my object that is optional. If the user originally sets a description and then later deletes it, I want to remove the description altogether from the object.
I do not want to overwrite the whole object (without the description attribute) because I have some count attributes on the object that I do not want to have to recalculate.
As far as I can tell in the documentation there isn't a way to do it and my workaround is to set the description as an empty string. Is that the recommended approach?
You're right: you cannot totally remove the attribute from an object with a partialUpdateObject operation. As a work-around you can set it to null, maybe that's enough for your use-case?
If you really want to delete the field you can :
Get your object with the search function
Store all fields values
Update (not partial update) your object without passing the field you want to delete

Why does AngularJS fail to initialize Select Option (drop list) when ngmodel is used with nested object?

I have a complex object which contains some nested arrays of objects.
Inside one of those inner objects is a value which is the id for an item in another list.
The list is just a look-up of Codes & Descriptions and looks like the following:
[
{ "id": 0, "value": "Basic"},
{ "id": 1, "value": "End of Month (EOM)"},
{ "id": 2, "value": "Fixed Date"},
{ "id": 3, "value": "Mixed"},
{ "id": 4, "value": "Extra"}
]
However, I only carry the value in the nested object.
The Select Option list (drop list) will display all of the values in the previous list so the user can make his/her selection.
Binding Via ng-model
I then bind the value returned from the Select/Option directly to the nested object.
That way, when the user makes a selection my object should be updated so I can just save (post) the entire object back to the server.
Initialization Is The Problem
The selection does work fine and I can see that the values are all updated properly in my nested object when a user selects. However, I couldn't get the UI (select/option) to be initialized to the proper value when I retrieved the (nested) object from the server.
Input Type Text Was Binding Properly
My next step was to add an text box to the form, bind it to the same ng-model and see if it got initialized. It did.
This is a large project I was working on so I created a plnkr.co and broke the problem down. You can see my plnkr in action at: http://plnkr.co/edit/vyySAmr6OhCbzNnXiq4a?p=preview
My plunker looks like this:
Not Initialized
I've recreated the exact object from my project in Sample 1 and as you can see the drop list is not selected properly upon initialization since the value(id) is actually 3, but the drop list doesn't show a selected value.
Keep In Mind: They Are Bound And Selecting One Does Update Values
If you try the plunker you will see that the values are bound to the select/option list because even in the samples which do not initialize properly, when you select an item the other bound items are instantly updated.
Got It Working : Hack!
I worked with it a long time and kept created fake objects to see which ones work and which don't.
It only works, once I changed the value object to one that looks like the following:
$scope.x = {};
$scope.x.y = 3;
Now, I can bind x.y (ng-model="x.y") to select/option and it initializes the select/option list as you would expect. See Sample 2 in the plunker and you will see that "mixed" (id value 3) is chosen as expected.
Additional One Works
I also learned that the following will work:
$scope.lastObj = {};
$scope.lastObj.inner = [];
$scope.lastObj.inner.push(3);
More Nesting
In that case I can bind lastObj.inner to the select/option list and again you can see in Example 3 that it still works. That is an object which contains an array which contains the value.
Minimal Nesting That Fails
However, Sample 4 in the plunker displays the final amount of nesting which does not work with the AngularJS binding.
$scope.thing = {};
$scope.thing.list=[];
$scope.thing.list.push({"item":"3"});
This is an object which contains an array which contains an object with a value. It fails to bind properly on the select/option but not the text box.
Can Anyone Explain That, Or Is It A Bug, Or Both?
Can anyone explain why the select/option fails to bind / initialize properly in this case?
A Final Note
Also, be strong and do not try to explain why you think the nesting of my objects should be different. That's not under discussion here, unless you can tell me that JavaScript itself does not support that behavior.
However, if you can explain that Angular cannot handle this deep of nesting and why, then that is a perfectly valid answer.
Thanks for any input you have.
You are messed up with primitive types. It means you should insert
$scope.vm.currentDocument.fieldSets[0].fields.push({"value":3});
instead of
$scope.vm.currentDocument.fieldSets[0].fields.push({"value":"3"});
Note the difference of {"value":3} and {"value":"3"}
First one defines an object with property "value" with Integer type, and the second one defines an object with property "value" with String type. As Angular checks type match, it becomes that ("3" === 3) evaluates as false, this is why angular cant find selected option.
This is how it supposed to work.
Also note that - as Armen points out - objects are passed by reference as opposed to primitives which are pass-by-value.
Because of this fact, normally initializing a select box via ngModel from JSON (say, from a $resource record) you will need to set the model value to the specific array element/object property that is being internally checked for equality by Angular to the elements in the ngOptions (or repeated options elements with ng-values assigned to the same record objects). No two distinct objects in JS are considered equal, even if they have identical property names/values.
Angular has one way around this: use the "track by" clause in your ngOptions attribute. So long as you have a guaranteed-unique value (such as a record index from a db) Angular will check the value of the property between the model value and the records in ngOptions.
See https://docs.angularjs.org/api/ng/directive/select for more.

How to get multiple "listKey" values from a Struts 2 <s:select>?

I have a code like this:
<s:select id="s" list="list" listKey="id" listValue="displayValue">
When I get the value from the object I'll always get the id.
How can I change the "listKey" value dinamically so I could get for example, the name of the object (supposing other of my attributes besides id is name ) instead always de id?
I was trying some code in jQuery like this:
function changeListKey(){
var id = $("#s").val();
$('#s').attr('listKey','name');
var name = $("#s").val();
document.write(name); // Only to test if I could get the value
}
When I execute it it doesn't seem to change the "lisKey" value so I could get another one, what would be the solution?
Thanks a lot in advance.
John Smith.
Why would you want to mix up what's used as the key value? That would make a mess on the server side.
In any case, listKey isn't an HTML attribute, it's a custom tag attribute, and is meaningless after the HTML has been rendered and sent to the client. You would need to iterate over the HTML select element's options collection and change the values on the options.
All this said, you'd be much better off doing any bizarre manipulations like this in the action itself, and exposing only the desired key/value pairs to the JSP, either in a list, or more easily, in a map. Using a map eliminates the need to provide listKey/listValue attributes--just use the map's key as the option text, and the value as the option's value.

How can I bind the selected text of a Select box to an object's attribute with Knockout JS, or anything else?

I have a select box pull down that I'm populating with a JSON list returned from a stored procedure, but unfortunately when I update the linked object I need to return the selected text of the pulldown, not the selected index like one would think (poor database design, but I'm stuck with it for now and cannot change it).
Does anyone have any ideas what I can do to keep the selected text synced with the appropriate javascript object's attribute?
You could keep both, the value and the text, if you use subscribers.
For instance, if each of your javascript objects look like this:
var optionObject = {
text:"text1"
value: 1
}
Then your binding would look like:
Where 'OptionsObjects' is a collection of optionObject and selectedOption
has two observable properties: text and value.
Finally you subscribe to the value property of the selectedOption:
viewModel.selectedOption.value.subscribe(function(newValue){
var optionText = viewModel.OptionsObjects[newValue].text;
viewModel.selectedOption.text(optionText);
});
Then if you want to see the new selected option text when the value is changed,
you could have a binding as follows:
<span data-bind:"text:selectedOption.text"></span>
In your particular case you would return selectedOption.text().
So yes, you got what I was getting at. Use the text as the value for the select options rather than using an index. The value really should be something useful, I can't think of any case where I've ever used an index. A number sure, but a number that relates to the application's models in some way (like an id from a database), not to the number of items in the select box.
Well done.

Categories

Resources