Observable inside Observable array that track two elements KO js - javascript

Array of 3 radio box and input text that are tied together, selection of radio would dynamically pop text that user can add on top of. I'm able to populate the text box, but can't track changes of both afterward as I need some sort of observable that trace both change and give me the total value of both (e.g. 'File: c:\temp\data.cs'
Here my HTML
<!-- ko foreach: includes -->
<div class="col-md-3 mt-3 offset-3 ">
<input class="col-md-2 " type="radio" value="file:" data-bind="checked: type, attr: { name: name }">File
<input class="col-md-2" type="radio" value="dir:" data-bind="checked: type, attr: { name: name }">Dirs
<input class="col-md-2" type="radio" value="glob:" data-bind="checked: type, attr: { name: name }">Glob
</div>
<div class=" col-md-6 pt-3 ">
<input type="text" class="form-control" required data-bind="attr: { name: name } , value: value">
</div>
<!-- /ko -->
</div>
<div class="col-sm-3 mt-4 mb-4 offset-4" id="firstPath">
<button type="button" class="form-control btn btn-info ml-3" data-bind="click: addInclude">Add new include line</button>
</div>
And my JS
self.includes = ko.observableArray([{
name: "package[][includes][0]",
type: "file:",
value: ko.observable()
}]);
self.addInclude = function () {
self.includes.push({
name: `package[][includes][${includeCounter++}]`,
type: `file`,
value: ko.observable("file")
});
};
How to make the value property in includes observable array track both radio selection + input text value for the related row ?
I tried Ko.Computed but the issue is when initialing the type in includes observable is not define yet for relative row (default value for type is file)

The type member should be observable. So, through subscribe, you can set the value of value each time type changes.
function myViewModel() {
var self = this;
self.includeCounter = 0;
self.includes = ko.observableArray([]);
self.addInclude = function () {
var type = ko.observable('file:');
var value = ko.observable('file:');
type.subscribe((newValue) => {
value(newValue);
}, self);
var item = {
name: `package[][includes][${self.includeCounter++}]`,
type: type,
value: value
};
self.includes.push(item);
};
self.addInclude();
}
var vm = new myViewModel();
ko.applyBindings(vm);

Related

Bind TextBox, date and dropdownlist value to parameter angularJS wcfRest

I have an angularJS using WCFrest Project
I create dropdownlist and datepicker for parameter to filter showed data.
Search Form can be seen on picture below
This is the html code
<!--Date From-->
<div class="col-md-4">
<input id="txtOldDate" type="date" value="2000-01-01" class="datepicker" />
</div>
<!--Date To-->
<div class="col-md-1">
<label for="labelTo" class="control-label">To</label>
</div>
<div class="col-md-4">
<input id="txtNewDate" type="date" class="datepicker" />
<!-- Set default date value to now-->
<script>
document.getElementById('txtNewDate').value = new Date().toISOString().substring(0, 10);
</script>
</div>
<!--Departement-->
<div class="col-sm-4">
<div class="dropdown">
<select class="form-control" ng-model="DdlDeptManager" ng-change="DdlManager(DdlDeptManager)">
<option ng-repeat="d in GetDeptManager" value="{{d.Department}}">{{d.Department}}</option>
</select>
</div>
</div>
<!--Employee-->
<div class="dropdown">
<!-- #departemen parameter from DdlDeptManager -->
<select id="ddlManagerApproval" ng-model="DdlManager" class="form-control">
<option ng-repeat="m in GetManager" value="{{m.UserName}}">{{m.FullName}}</option>
</select>
</div>
<!--Button Show-->
<div class="col-md-2">
<input id="btnSubmit" type="button" class="btn btn-primary" ng-click="SearchApproval()" value="Show" />
</div>
This is my control approvalCtrl.js
//Control for search purposes
$scope.SearchApproval = function() {
var search = {
//employeeID: $scope.employeeID,
oldDate: $scope.oldDate,
newDate: $scope.newDate,
departemen: $scope.departemen,
approver: $scope.approver
}
var promiseGet = GetApproval.GetApprovalData(search);
//GetApprovalData();
promiseGet.then(function(pl) {
$scope.GetApprovalData = pl.data
},
function(errorPl) {
console.log('Some Error in Getting Records.', errorPl);
});
}
This is the service.js, for employeeID because the session is not created, i forced add value to it on the uri
this.GetApprovalData = function(employeeID, oldDate, newDate, departemen, approver) {
return $http.get("http://localhost:51458/ServiceRequest.svc/GetApproval?employeeID=" + "11321" + "&oldDate=" + oldDate + "&newDate=" + newDate + "&departemen=" + departemen + "&approver=" + approver);
};
My Question is, how to make the value on datepicker id = txtOldDate to give a paramater value to oldDate, txtNewDate to newDate, and other dropdownlist to departemen and approver parameter?
Thanks in Advance.
Hi Randy I have reproduced your code without service sorry for that. Used hardcode array to populate dropdown. Kindly check this url
https://plnkr.co/edit/eSriV68HkhQhzt1yE6DE?p=preview
$scope.GetDeptManager = [{
Department : 'department1'
}, {
Department: 'department2'
}];
$scope.GetManager = [{
FullName : 'manager1'
}, {
FullName: 'manager2'
}]
And you have to assign ng-model values for your input elements so that you will get those values in controller.

Angularjs: input for ng-repeat elements

Sorry for my language skills, hope you understand all.
I need to make inputs for ng-repeat elements, to pass input data to http post.
For example: i have 4 elements, for all elements i make inputs, and f.e:
elem1- input: 1
elem2- input: 4
elem3- input: 1
elem4- input: 2
Here is my code:
.panel-body.note-link ng-repeat=("meal in mealsList track by $index")
a data-toggle="tab"
h4.pull-right.text-muted
| {{meal.price}} zł
h4.text-success
i.fa.fa-close.text-danger<> ng-click="removeMeal($index)" style="cursor: pointer;font-size: 15px;"
| {{meal.name}} {{$index}}
input.form-control type="number" ng-model="example"
| {{example}}
And i dont know, how to pass input data to controller.
Any tips,tricks?
angular.module('yourModule').controller('viewController', function($scope) {
$scope.mealList = [...];
$scope.example; //The input data will automatically bind to this variable.
});
If you want the input to change data within your meal object, then do this:
input.form-control type="number" ng-model="meal.example"
And then the property value of the meal object would bind to the input
Repeat through your mealList array and add the inputs.
Example: https://jsfiddle.net/ptzhL0uL/
Controller
function Controller1($scope) {
var vm = this;
vm.items_saved = false;
vm.mealList = [{
price: '2.99',
name: 'Pizza'
}, {
price: '1.99',
name: 'Chips'
}, {
price: '4.99',
name: 'Beer'
}];
vm.addNewItem = addNewItem;
vm.saveItems = saveItems;
function addNewItem() {
vm.mealList.push({});
}
function saveItems() {
vm.items_saved = true;
}
}
HTML
<button ng-click="ctrl.addNewItem()" class="btn btn-default">Add Item</button>
<div ng-repeat="item in ctrl.mealList">
<input type="text" ng-model="item.name">
<input type="text" ng-model="item.price">
<input type="number" ng-model="item.quantity">
</div>
<button ng-click="ctrl.saveItems()" class="btn btn-primary">Save</button>
<hr>
<div ng-if="ctrl.items_saved">
<h4>Here is your meal list:</h4>
<ul>
<li ng-repeat="item in ctrl.mealList">{{item.quantity}}{{item.name}} at ${{item.price}} each</li>
</ul>
</div>
Just attach it to the ngModel directive.
<div ng-repeat="item in array">
{{ item.output }}
<input ng-model="item.output" />
</div>

Knockoutjs computed not updated from observableArray

I want a computed to be updated when an observable array is updated. The array is populated with questions and answer (Yes or No). When the user change the answer of a question, I want some region to be visible or not.
So the computed is5B should be true if one of the question is answered "oui" and this should make the sections visible.
The is5B computed is only calculated at initialization and is not fired when the array is updated (it is updated, I checked with a breakpoint)
Here's the view model:
var section5Model = ko.validatedObservable({
Questions5A: ko.observableArray(GetQuestions('5A')),
Questions5B: ko.observableArray(),
Questions5C: ko.observableArray(),
ContactAQ: ko.observable(),
Date: ko.observable(''),
Heure: ko.observable(''),
CategorisePar: ko.observable(''),
DateCategorise: ko.observable(''),
RepOuiNon: [{ label: 'Oui', value: 0 }, { label: 'Non', value: 1 }]
});
section5Model().is5B = ko.computed(function () {
this.Questions5A().forEach(function (item) {
if (item.reponse == 'Oui') {
return true;
}
});
}, section5Model());
Here's the markup:
<div id="sectionContainer">
<div id='S5FormBlock1' class="formSection5">
<div id="QSection5A" data-bind="foreach: Questions5A">
<div class='mockTable'>
<div class="column200 centerLabel"><span data-bind="text: Texte"></span></div>
<div class="grayRoundBorder padR10" data-bind="foreach: $parent.RepOuiNon">
<input type="radio" data-bind="value: label, attr : {name: $parent.ID}, checked: $parent.reponse" /><span data-bind="text: label"></span>
</div>
</div>
<p />
</div>
<div data-bind="visible: is5B">Il s'agit d'une plainte qualité</div>
<div id="QSection5B" data-bind="visible: is5B,foreach: Questions5B">
<div class='mockTable'>
<div class="column200 centerLabel"><span data-bind="text: Texte"></span></div>
<div class="grayRoundBorder padR10" data-bind="foreach: $parent.RepOuiNon">
<input type="radio" data-bind="value: label, attr : {name: $parent.ID}, checked: $parent.reponse" /><span data-bind="text: label"></span>
</div>
</div>
<p />
</div>
<div data-bind="visible: is5C">Il s'agit d'une plainte d'insatisfaction</div>
<div id="QSection5C" data-bind="visible: is5C,foreach: Questions5C">
<div class='mockTable'>
<div class="column200 centerLabel"><span data-bind="text: Texte"></span></div>
<div class="grayRoundBorder padR10" data-bind="foreach: $parent.RepOuiNon">
<input type="radio" data-bind="value: label, attr : {name: $parent.ID}, checked: $parent.reponse" /><span data-bind="text: label"></span>
</div>
</div>
<p />
</div>
</div>
</div>
The problem that you have is that item.response is not observable. So if it change KnockoutJS doesn't know about that. To fix this you have to change that to observable
section5Model().is5B = ko.computed(function () {
this.Questions5A().forEach(function (item) {
if (item.reponse() == 'Oui') {
return true;
}
});
}, section5Model());
Computed are functions that are dependent on one or more other observables, and will automatically update whenever any of these dependencies change. so in your case no observable inside your computed function. so make at-least one variable in side computed as observable. in your case please make the item.response as observable. for that you need to return observable variable on GetQuestions('5A')
Please do Questions5A observableArray as like
var section5Model = ko.validatedObservable({
Questions5A: ko.observableArray([
{reponse : ko.observable('reponse 1 ') },
{reponse : ko.observable('reponse 2') },
/* other objects */
]),
/* other code */

Getting data from the server and using ng-options in select control is failing to show options

this my HTML
<div ng-app="timeTable" ng-controller="addCoursesCtrl">
<button class="btn btn-primary" ng-click="addNewCourse()">Add New Course</button><br/><br/>
<fieldset ng-repeat="choice in choices">
<div class="row">
<div class="col-md-6">
<select class="form-control" ng-model="choice.type" ng-options="s for s in coursetoAdd">
<option value="{{s.shortCut}}">{{s.name}}</option>
</select>
</div>
<div class="col-md-6">
<input type="text" placeholder="Enter Course Name" name="" class="form-control" ng-model="choice.course"/>
</div>
</div>
<br/>
</fieldset>
<button class="btn btn-primary" ng-click="convertAndSend()">Submit</button>
</div>
this the js
var timeTable = angular.module("timeTable",[]);
timeTable.controller("addCoursesCtrl", function ($scope,$http) {
$scope.choices = [{ course: '', type: '' }];
$scope.coursetoAdd ;
$http.get("/Semster/getSuggtedCourses").then(function (response) {
$scope.coursetoAdd = response.data;
});
$scope.addNewCourse = function () {
var newITemNo = $scope.choices.length + 1;
$scope.choices.push({ course: '', type: '' });
};
$scope.convertAndSend = function () {
var asJson = angular.toJson($scope.choices);
console.log(asJson);
$http.post('/Semster/Add', asJson);
};
});
this code bind an object {"course":...,"type":....} every time you click on add course ,and add input field dynamically , my problem is with select control,I'm getting the data from server and use it with ng-optin ,but all it shows it's just [object Object] in select option not the real value.
Assuming that the data returned from getSuggestedCourses is an array of objects, the ng-options selector:
s for s in courseToAdd
will bind s to each object in the array. You need to bind to the fields in the object like this
s.value as s.name for s in courseToAdd

How to implement paging in "with" bindings in knockout

I have a requirements in my project where I need to put my selected item in the Modal and user can click next to show the next item.
I am using a with binding to display the content of selected in a form. I don't have an idea on how can I apply paging inside a "With" binding.
<div class="container" data-bind="with: itemForEditing">
<div id="riskRegisterForm" class="modal hide fade">
<div class="modal-header" style="background:#4bafef; height: 30px;">
<h5 style="color:#FFFFFF; font:16px Arial;">Item</h5>
</div>
<div class="modal-body" style="background:#fff">
<div>
<form class="form-horizontal">
<div class="control-group">
<label class="control-label" for="itemName">Name</label>
<div class="controls">
<input type="text" id="itemName" data-bind="value: name" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="itemPrice">Price</label>
<div class="controls">
<input type="number" step=".01" id="itemPrice" data-bind="value: price" />
</div>
</div>
</form>
</div>
</div>
<div class="modal-footer">
<button type="button" data-dismiss="modal" class="btn" data-bind="click:$parent.revertItem">Cancel</button>
<button type="button" data-dismiss="modal" class="btn" data-bind="click:$parent.acceptItem">Update</button>
</div>
<span><a href=#>next</a></span>
<span><a href=#>prev</a></span>
</div>
</div>
when I click the next it should autmatically select the next records and put in the contorls. Here is the JsFiddle http://jsfiddle.net/ramon26cruz/Tt96J/6/
I've had a go at this. I changed my tack from above. Basically I created 2 method, a next and a prev. In the methods I find the index of the selected / editable object in the array and the either increment or decrement based on which method has been used. I then update the selected and editable property objects:
var Item = function(data) {
this.name = ko.observable();
this.price = ko.observable();
//populate our model with the initial data
this.update(data);
};
//can pass fresh data to this function at anytime to apply updates or revert to a prior version
Item.prototype.update = function(data) {
this.name(data.name || "new item");
this.price(data.price || 0);
};
var ViewModel = function(items) {
this.index = 0;
//turn the raw items into Item objects
this.items = ko.observableArray(ko.utils.arrayMap(items, function(data) {
return new Item(data);
}));
//hold the currently selected item
this.selectedItem = ko.observable();
//make edits to a copy
this.itemForEditing = ko.observable();
this.selectItem = this.selectItem.bind(this);
this.acceptItem = this.acceptItem.bind(this);
this.revertItem = this.revertItem.bind(this);
this.next = this.next.bind(this);
this.prev = this.prev.bind(this);
};
ko.utils.extend(ViewModel.prototype, {
//select an item and make a copy of it for editing
selectItem: function(item) {
this.selectedItem(item);
this.itemForEditing(new Item(ko.toJS(item)));
},
next:function(){
var pos = this.items.indexOf(this.selectedItem()) + 1;
if(pos > this.items().length - 1){pos = 0};
this.selectedItem(this.items()[pos]);
this.itemForEditing(new Item(ko.toJS(this.items()[pos])));
},
prev:function(){
var pos = this.items.indexOf(this.selectedItem()) - 1;
if(pos < 0){pos = this.items().length - 1};
this.selectedItem(this.items()[pos]);
this.itemForEditing(new Item(ko.toJS(this.items()[pos])));
},
acceptItem: function(item) {
var selected = this.selectedItem(),
edited = ko.toJS(this.itemForEditing()); //clean copy of edited
//apply updates from the edited item to the selected item
selected.update(edited);
//clear selected item
this.selectedItem(null);
this.itemForEditing(null);
},
//just throw away the edited item and clear the selected observables
revertItem: function() {
this.selectedItem(null);
this.itemForEditing(null);
}
});
ko.applyBindings(new ViewModel([
{ name: "Cheese", price: 2.50 },
{ name: "Pepperoni", price: 3.25 },
{ name: "Deluxe", price: 4.25 }
]));
Here's a link to my JS Fiddle.
One way to do it would be like this:
<div class="container" data-bind="with: itemForEditing">
<!-- ... -->
<span>next</span>
<span>prev</span>
</div>
and
ko.utils.extend(ViewModel.prototype, {
// offset the selected item by a certain amount (i.e. -1/+1 for next/prev)
offsetItem: function (by) {
var items = this.items(),
i = ko.utils.arrayIndexOf(items, this.selectedItem()),
newItem = (i > -1) ? items[i + by] : null;
if (newItem) {
this.selectItem(newItem);
}
},
prevItem: function () {
this.offsetItem(-1);
},
nextItem: function () {
this.offsetItem(1);
},
/* ... */
}
See it live http://jsfiddle.net/Tt96J/11/

Categories