knockout observable array set selected value - javascript

I am trying to populate "Select" using knockout data-bind option for a list of values and set one of the values as "selected" by default.
There are two server requests,
Get the list of values (dataRepository.GetLifelines)
Set one of the values as Selected from the list. (dataRepository.GetMockSelectedLifeline)
First requirement has been addressed. data-bind to a select is working fine with "Selected" value.
I am having issue with setting the default "Selected Value" in the list. Can someone please help me. method is this.selectValue. It is trying to set the selectedLifeline to the matching "Name".
function LifelineViewModel() {
this.lifelines = ko.observableArray([{}]);
this.selectedLifeline = ko.observable();
this.updateData = function (data) {
var boundUpdate = bind(function (value) {
this.lifelines.push(value);
}, this);
$.each(data, function (index, item) {
boundUpdate(item);
});
dataRepository.GetMockSelectedLifeline(bind(this.selectValue, this));
}
this.selectValue = function (data) {
this.selectedLifeline = ko.utils.arrayFirst(this.lifelines, function (lifeline) {
return lifeline.Name === data.Name;
});
}
}
LifelineViewModel.prototype.Init = function () {
var boundUpdateData = bind(this.updateData, this);
dataRepository.GetLifelines(boundUpdateData);
}
var bind = function (func, thisValue) {
return function () {
return func.apply(thisValue, arguments);
}
}

As selectedLifeline is an observable you are not setting its value correctly.
Could you try this. Instead of:
this.selectValue = function (data) {
this.selectedLifeline = ko.utils.arrayFirst(this.lifelines, function (lifeline) {
return lifeline.Name === data.Name;
});
}
.. something like...
this.selectValue = function (data) {
this.selectedLifeline(ko.utils.arrayFirst(this.lifelines, function (lifeline) {
return lifeline.Name === data.Name;
}));
}

Related

Push() not working when called from inside getJSON()

I'm currently using the jQuery drag and drop formbuilder plugin. Now, I want to fetch drag and drop elements from my database and add those element to my drag and drop builder.
This is my request function:
function getElements(){
$.getJSON( getContextPath() + "/api/elements/get", function (data){
$.each(data, function(key, val) {
addElement();
});
});
}
Now, I want to add them to the formbuilder instance (I use this example and I use some pre-defined values):
function addElement(){
if (!window.fbControls) window.fbControls = [];
window.fbControls.push(function(controlClass) {
console.log("HERE");
class controlStarRating extends controlClass {
static get definition() {
return {
icon: '🌟',
i18n: {
default: 'Star Rating'
}
};
}
configure() {
this.js = '//cdnjs.cloudflare.com/ajax/libs/rateYo/2.2.0/jquery.rateyo.min.js';
this.css = '//cdnjs.cloudflare.com/ajax/libs/rateYo/2.2.0/jquery.rateyo.min.css';
}
build() {
return this.markup('span', null, {id: this.config.name});
}
onRender() {
let value = this.config.value || 3.6;
$('#'+this.config.name).rateYo({rating: value});
}
}
// register control
controlClass.register('starRating', controlStarRating);
return controlStarRating;
});
}
Unfortunately, my console.log("HERE") is not called, so it seems like it alle stops there. The weird thing is, if I use this as my request function the function is properly executed:
function getElements(){
var allElementsData = ["test"];
// $.getJSON( getContextPath() + "/api/template/get", function (data){
// });
$.each(allElementsData, function(key, val) {
addElement();
});
}
What is the problem?
In the function addElement you are pushing another function into the array window.fbControls. But that second function is only placed in the array not executed. You could for example execute it with this statement: window.fbControls[0](). Then you would see the console.log("HERE")

How to return a list of available options in a select element in Protractor?

I am trying to retrieve all the options available in select element using Protractor. I am having trouble figuring out how to do this because I'm a JavaScript beginner and therefore am having trouble determining how to return the array and not a promise.
I've tried this:
getOptions = function () {
var self = this;
var availableOptions = [];
return this.selector.click().then(function () {
self.selectorOptions.then(function (options) {
options.forEach(function (option) {
option.getAttribute("value").then(function (value) {
availableOptions.push(value);
});
});
});
}).then(function () {
return availableOptions;
});
};
This returns a promise and not the array which I want. I also tried this:
getOptions = function () {
var self = this;
var availableOptions = [];
this.selector.click().then(function () {
self.cloudletTypeOptions.then(function (options) {
options.forEach(function (option) {
option.getAttribute("value").then(function (value) {
availableOptions.push(value);
});
});
});
});
return availableOptions;
};
When I do this and call the method from a test and try to print the result, it is 'undefined'. What do I need to do to ensure that the return value is defined and is an array? Barring that, how do I force the promise to resolve?
From what I understand, you are looking for map():
Apply a map function to each element within the ElementArrayFinder.
The callback receives the ElementFinder as the first argument and the
index as a second arg.
getOptions = function () {
var self = this;
return this.selector.click().then(function () {
return self.selectorOptions.map(function (option) {
return option.getAttribute("value").then(function (value) {
return value;
});
});
});
};

How to use a variable returned by $.getJSON in another function

I have a javascript object with several properties and methods. I want to call the first method within the second, in order to get the default number of ingredients of a pizza and compare it with another value. However, I detect that no-value is present in the comparison of the second method.
Googling about this issue, I saw that I have to make a callback in the first method, but it didn't work for me. So, how can I be sure that the property obj.app.defaultIngredients will have a value returned by the JSON, when a 'click' event in the second method will occur? And, in that moment, I can compare the value as you also can see in the second method?
There is my (not working) code:
obj = {};
obj.app = {
defaultIngredients: '',
getDefaultIngredientsNumber: function() {
$.getJSON('/sites/all/json/pizza.json', function(data) {
var node = $('.node').attr('data-nid'),
node = 'node-' + node; // returns something like 'node-3'
$.each(data, function(key, val) {
// This returns an integer
obj.app.defaultIngredients = parseInt(data[node].general.default_ingredients);
});
}).done(function() {
return obj.app.defaultIngredients;
});
},
customAddToCart: function() {
$('#button').click(function(){
var defaultIngredients = obj.app.getDefaultIngredientsNumber();
var selectedIngredients = 0;
if defaultIngredients >= selectedIngredients) {
alert('Add some ingredients');
}
}
}
};
Some help with this will be very apreciated.
getDefaultIngredientsNumber: function(callback) {
$.getJSON('/sites/all/json/pizza.json', function(data) {
var node = $('.node').attr('data-nid'),
node = 'node-' + node; // returns something like 'node-3'
$.each(data, function(key, val) {
obj.app.defaultIngredients = parseInt(data[node].general.default_ingredients);
});
callback(obj.app.defaultIngredients)
})
},
customAddToCart: function() {
$('#button').click(function(){
obj.app.getDefaultIngredientsNumber(function(defaultIngredients) {
var selectedIngredients = 0;
if (defaultIngredients >= selectedIngredients) {
alert('Add some ingredients');
}
})
})
}
I may be missing something since seems too easy ..
});
}).done(function(data) {
return anotherfunction(data);
});
Or instead of this:
customAddToCart: function() {
$('#button').click(function(){
var defaultIngredients = obj.app.getDefaultIngredientsNumber();
var selectedIngredients = 0;
if defaultIngredients >= selectedIngredients) {
alert('Add some ingredients');
}
}
}
};
I would use this:
customAddToCart: function() {
$('#button').click(function(){
obj.app.getDefaultIngredientsNumber("alert");
}
}
};
And in the getDefaultIngredientsNumber I would check if alert is set, then perform the alert..

Knockout.js: computed observable not updating as expected

Edit: Added code for function populateDropdown and function isSystemCorrect (see bottom)
Edit 2 I have narrowed it down a bit and the problem seems to arise in the arrayFilter function in the computed observable. This returns an empty array, no matter what I try. I have checked that self.testsuites() looks ok right before filtering, but the filtering still fails.
I have a problem with my computed observable, filteredTestsuites.
As you can see from the screendump, the testsuites observable is populated correctly, but the computed observable remains empty. I have also tried choosing another option than "Payment" from the dropdown menu, to see if this will trigger the observable, it did not.
I would think the computed observable would be updated every time self.testsuites() or self.dropdownSelected() was changed, but it doesnt seem to trigger on neither of them.
What am I doing wrong here?
I simply want to make the computed observable filter the testsuites after the chosen dropdown option, every time either of them change.
function ViewModel() {
var self = this;
// The item currently selected from a dropdown menu
self.dropdownSelected = ko.observable("Payment");
// This will contain all testsuites from all dropdown options
self.testsuites = ko.mapping.fromJS('');
// This will contain only testsuites from the chosen dropdown option
self.filteredTestsuites = ko.computed(function () {
return ko.utils.arrayFilter(self.testsuites(), function (testsuite) {
return (isSystemCorrect(testsuite.System(), self.dropdownSelected()));
});
}, self);
// Function for populating the testsuites observableArray
self.cacheTestsuites = function (data) {
self.testsuites(ko.mapping.fromJS(data));
};
self.populateDropdown = function(testsuiteArray) {
for (var i = 0, len = testsuiteArray().length; i < len; ++i) {
var firstNodeInSystem = testsuiteArray()[i].System().split("/")[0];
var allreadyExists = ko.utils.arrayFirst(self.dropdownOptions(), function(option) {
return (option.Name === firstNodeInSystem);
});
if (!allreadyExists) {
self.dropdownOptions.push({ Name: firstNodeInSystem });
}
}
};
}
$(document).ready(function () {
$.getJSON("/api/TestSuites", function (data) {
vm.cacheTestsuites(data);
vm.populateDropdown(vm.testsuites());
ko.applyBindings(vm);
});
}
Function isSystemCorrect:
function isSystemCorrect(system, partialSystem) {
// Check if partialSystem is contained within system. Must be at beginning of system and go
// on to the end or until a "/" character.
return ((system.indexOf(partialSystem) == 0) && (((system[partialSystem.length] == "/")) || (system[partialSystem.length] == null)));
}
As suggested in a comment - rewrite the cacheTestsuites method:
self.testsuites = ko.observableArray();
self.filteredTestsuites = ko.computed(function () {
return ko.utils.arrayFilter(self.testsuites(), function (testsuite) {
return (isSystemCorrect(testsuite.System(), self.dropdownSelected()));
});
});
self.cacheTestsuites = function (data) {
var a = ko.mapping.fromJS(data);
self.testsuites(a());
};
The only thing different here is the unwrapping of the observableArray from the mapping function.

KnockoutJs computed array not calculated correctly

The code is as follows: EmployeeModel is the viewModel and the problem is that when I change an item's property - deletedFlag in employees (obs array), deletedItems is not updated.
How can i fix this?
function Employee(data) {
this.employeid = ko.observable(data.employeid);
this.name = ko.observable(data.name);
this.isactive = ko.observable(data.isactive);
this.deletedFlag = ko.observable(false);
}
var EmployeeModel = function () {
var self = this;
self.employees = ko.observableArray([]);
self.deletedItems = ko.computed(function () {
return ko.utils.arrayFilter(self.employees(), function (item) {
return item.deletedFlag == true;
});
}, this);
}
EDIT: and the following code marks one item from the array for deletion
self.removeEmployee = function (employee) {
employee.deletedFlag(true);
};
The property deletedFlag is an observable, therefore you need to retrieve its current value by invoking it as a function (you cannot compare it directly to any value):
self.deletedItems = ko.computed(function () {
return ko.utils.arrayFilter(self.employees(), function (item) {
return item.deletedFlag() == true; // <===
});
}, this);

Categories

Resources