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 */
Related
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);
Hi all I am new to angularjs could anybody help me please? All what I need when I click a button the first checkbox in ng-repeat list to be checked. Am I doing anything wrong? Here is my code:
Checkbox
<fieldset class="top5">
<legend title="Categories"><span class="info blackLabelUpper"><b>Dish Categories</b><span class="TextCtrlReqBgImage"> </span></span></legend>
<span class="checkbox-list" ng-repeat="dishType in dishTypes">
<input type='checkbox' ng-click="toggleDishType(dishType)" ng-model="dishType.checked" value="{{dishType}}" ng-checked="selectedDish.Type.indexOf(dishType) > -1">
{{dishType}}<br />
</span>
</fieldset>
Button
<kendo-button id="btnNewDish" class="k-primary" ng-click="onNewDishClick(true)">
<i class="fa fa-plus fa-lg" aria-hidden="true"></i>New Dish
</kendo-button>
Function
scope.onNewDishClick = function (showNewDIshMessage) {
scope.dishTypes[0].dishType = true;
}
When you use ng-model on your inputs you don't need to use value to get result because ng-model save changes on self.
Feel free to ask question, and this sample maybe helps you.
var app = angular.module("app", []);
app.controller('ctrl', function($scope){
$scope.items = [
{somthing: false, title: 'a'},
{somthing: false, title: 'b'},
{somthing: false, title: 'c'},
{somthing: false, title: 'd'},
{somthing: false, title: 'e'}
]
$scope.checkAll = function(){
angular.forEach($scope.items, function(item){
item.somthing = !item.somthing;
});
}
$scope.checkFirstItem = function(){
$scope.items[0].somthing = !$scope.items[0].somthing;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<ul>
<li ng-repeat="item in items">
<input type="checkbox" ng-model="item.somthing">
{{item.somthing}}
{{item.title}}
</li>
</ul>
<button ng-click="checkAll()">check all</button>
<button ng-click="checkFirstItem()">check first item</button>
</div>
<div ng-repeat="restorent_type in restaurant_types" style="margin:5px;" class="col col-offset-10">
<label class="item item-radio radio-label {{restorent_type.RESCOD}}">
<input type="checkbox" name="group" ng-model="restorent.types" value="{{restorent_type.RESCOD}}" ng-click="filters.RESCOD = restorent_type.RESCOD" ng-checked="$first">
<div class="item-content">
{{restorent_type.RESCOD}}
</div>
<i class="radio-icon ion-checkmark"></i>
</label>
</div>
Or you can use the :
ng-model="dishType.checked" ng-init="dishType.checked=true"
I think the Function definition should be like this :
scope.onNewDishClick = function (showNewDIshMessage) {
scope.dishTypes[0].checked = true;
}
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>
I'm starting to use KnockoutJS and of course doubts comes to me. So I have this jQuery code:
$.post("someUrl", $form.serialize(), 'json').done(function (data, textStatus, jqXHR) {
$.cookie("stepOneSave", true);
// here I should update the attributes from response in data
}).fail(function () {
return false;
}).always();
And then in my view (it's a Twig template since this is part of Symfony2 project) I have this:
<fieldset class="rpni-border">
<legend class="rpni-border">Datos de Solicitud</legend>
<div class="spacer10"></div>
<div class="col-md-3">
<p><strong>Number:</strong></p>
<p><strong data-bind="text: currIDSolicitud"></strong></p>
</div>
<div class="col-md-3">
<p>Request Type: </p>
<p><strong data-bind="text: currTipoSolicitud"></strong></p>
</div>
<div class="col-md-3">
<p>Office: </p>
<p><strong data-bind="text: currOficinaRegional"></strong></p>
</div>
<div class="col-md-3">
<p>Status: </p>
<p><strong data-bind="text: currEstadoSolicitud"></strong></p>
</div>
</fieldset>
Using the info provided how do I update the attributes and bind them to the view? This is my first time with Knockout and I start reading here but it's not clear to me this, can any give me some help?
Ok, let say you have this data returned from server using ajax request
data: [
{
id: 1,
name: 'John',
age: 17
},
{
id: 2,
name: 'Doe',
age: 20
}
];
inside a viewmodel function you need to define one property as a observableArray to handle above data:
var viewModel = function()
{
var self = this;
self.friends = ko.observableArray([]);
};
now from code above you already have empty friends observableArray, next you need to write your ajax request to fetch data from server then insert it to observableArray:
var ViewModel = function()
{
var self = this;
self.friends = ko.observableArray([]);
};
$(document).ready(function()
{
var viewmodel = new ViewModel();
ko.applyBindings(new viewmodel());
$.ajax({
url: '/example',
// more ajax options...
success: function(response)
{
viewmodel.friends(response.data);
}
});
});
and here is the view will look alike:
<div data-bind="foreach: $root.friends">
<div class="row">
<div class="col-md-6" data-bind="text: name"></div>
<div class="col-md-6" data-bind="text: age"></div>
</div>
</div>
So, if you want to add class attribute, do something like this:
<div data-bind="foreach: $root.friends">
<div class="row" data-bind="css: age < 18 ? 'kid' : 'adult'">
<div class="col-md-6" data-bind="text: name"></div>
<div class="col-md-6" data-bind="text: age"></div>
</div>
</div>
Or maybe you want to add href attribute, do something like this:
<div data-bind="foreach: $root.friends">
<div class="row" data-bind="css: age < 18 ? 'kid' : 'adult'">
<div class="col-md-12" data-bind="text: name"></div>
<a data-bind="text: age, attr: { href: age < 18 ? 'http://kid.com' : 'http://adult.com' }"></a>
</div>
</div>
Read more about attr binding here
p/s: This is not a good approach, but it should be working !
I have a viewmodel in javascript that includes checkbox items.
Javascript is here:
var data = [
{"name": "Computers",
"subcategories":[{"name":"Mac"}, {"name":"Desktop"}]},
{"name": "Mobile Phones" ,
"subcategories":[{"name":"Nokia"}, {"name":"Sony"}, {"name":"iPhone"}]}
];
var viewModel = {
categories: ko.observableArray(data),
selectedCategories: ko.observableArray()
};
ko.applyBindings(viewModel);
HTML code is like this:
<p>Categories: </p>
<div data-bind="foreach: categories">
<div>
<input type="checkbox" data-bind="checked: $parent.selectedCategories, checkedValue: $data.subcategories"/> <label data-bind="text: name"></label>
<ul data-bind="foreach: subcategories">
<li><input type="checkbox" data-bind="checked: $root.selectedCategories, checkedValue: $data"/> <label data-bind="text: name"></label></li>
</ul>
</div>
</div>
<p>Selected items: </p>
<div data-bind="text: ko.toJSON(selectedCategories)"></div>
When I click the main checkbox of a category (Computers) subcategories(Mac, Desktop) didn't populated. So I should clik again Mac and Desktop checkbox, but duplicated records inserting in selecteditems.
Here is jsfiddle code.
What's happening is the checkedValue binding in the parent category is storing the whole subcategories array as an array of objects when checked, when what I believe you want to happen is to store each object in the subcategories array individually. One way to accomplish that is with a click handler instead of checked and checkedValue.
JavaScript:
var data = [
{
"name": "Computers",
"subcategories": [{"name":"Mac"}, {"name":"Desktop"}]
},
{
"name": "Mobile Phones" ,
"subcategories": [{"name": "Nokia"}, {"name": "Sony"}, {"name": "iPhone"}]
}
];
var viewModel = {
categories: ko.observableArray(data),
selectedCategories: ko.observableArray(),
toggleCategory: function(category, event) {
var checked = event.target.checked;
ko.utils.arrayForEach(category.subcategories, function(item) {
viewModel.selectedCategories.remove(item);
if(checked) {
viewModel.selectedCategories.push(item);
}
});
return true;
},
};
ko.applyBindings(viewModel);
HTML
<p>Categories: </p>
<div data-bind="foreach: categories">
<div>
<input type="checkbox" data-bind="click: $root.toggleCategory"/> <label data-bind="text: name"></label>
<ul data-bind="foreach: subcategories">
<li><input type="checkbox" data-bind="checked: $root.selectedCategories, checkedValue: $data"/> <label data-bind="text: name"></label></li>
</ul>
</div>
</div>
<p>Selected items: </p>
<div data-bind="text: ko.toJSON(selectedCategories)"></div>
Notice the new toggleCategory method on the view model and the click: $root.toggleCategory binding that replaced the old checked and checkedValue bindings are the only pieces that have been changed.
Working JS Fiddle (tested in Chrome): http://jsfiddle.net/L2eWg/1/