make knockout array object visible based on an id value - javascript

All the examples I see are for DOM elements that are explicitly written on the page. In my case I am using the knockout foreach to create a list of items in my observable array:
<div class="tab-pane fade" id="recruiting">
<input type="text" data-bind="value: selectedOrgKey" id="orgSectionId" onchange="FlipOrgView()" style="visibility: hidden;" />
<ul class="list-unstyled" data-bind="foreach: orgs">
<li data-bind="attr: { id: 'orgSection' + orgId}" class="orgSection">
I am currently using a kludgy solution by using the onchange on an hidden element to grab the id and .show() it.
window.OrgDdlUpdated = function () {
$(".orgSection").hide();
var selectedOrgId = $('#orgDropDown').val();
//alert(selectedOrgId);
flipOrgView(selectedOrgId);
};
var flipOrgView = function (id) {
$('#orgSection' + id).show();
};
This technically works, the first time, but as I flip through it all, the selected id lags behind to where it shows the previous selection, not the current one. I know there are various ways to achieve this, so knockout or otherwise, how can i properly toggle the visibility of an array of objects using the knockout foreach method?

how about:
<div class="tab-pane fade" id="recruiting">
<input type="text" data-bind="value: selectedOrgKey" id="orgSectionId" style="visibility: hidden;" />
<ul class="list-unstyled" data-bind="foreach: orgs">
<li data-bind="visible: $parent.selectedOrgKey() === orgId(), attr: { id: 'orgSection' + orgId}" class="orgSection">
im not too sure in your example how you are setting selectedOrgKey but this should do the MVVM behavior i think you are getting at.

Related

How can we achieve product filter page using angularjs with multi selection of checkboxes?

I have created a tabular page in which i need to filter the table with filters using a left side facets boxes of different category but with multi-selection options and i need to use Angularjs for this requirement.
I need to check/uncheck using the clear filter selection .
Any helping library can help to achieve the same or we need to do some logic around the checkboxes to achieve this.
My checkbox code looks like this:
<div class="col-sm-2" style="padding-top: 10px; padding-bottom: 20px;">
<div class="facetBx sltBx" ng-show="tabFilters.length > 0">
<p class="facetBxTitle"><i class="fa fa-filter"></i> Filter Selection
<a class="clrSlt" ng-click="clearAllFilters();">Clear</a>
</p>
<div class="facetBxChld" id="uRslctn">
<ul>
<li ng-repeat="item in tabFilters">
<div class="crop">
<strong title="{{item}}">{{item}}</strong>
</div>
<i class="fa fa-remove rmvThs" style="font-size: 14px;color:#000;float: right;" ng-click="checkItem(item, item,false);"></i>
</li>
</ul>
</div>
</div>
<div class="facetBx" ng-repeat="item in filters">
<p class="facetBxTitle bomtype">{{item.label}}</p>
<div class="facetBxChld" id="bomFacet">
<ul class="multiselect" style="max-height: 140px;overflow-y: auto;">
<li ng-repeat="(k,v) in item.values">
<input type="checkbox" ng-model='isSelected' ng-click='checkItem(item.name, k, isSelected)'>
<span> {{k}} ({{v}})</span>
</li>
<li ng-show="value.length == 0">
No Data Available.
</li>
</ul>
</div>
</div>
</div>
Below website are the reference of the code which i am trying to build:
www.jabong.com
The UI(HTML) is done but i am facing the trouble in the maintaining the checking and un-checking of the checkboxes which are not clearing off.
I believe i need to code something in the ng-model of checkbox to achieve it but i am not able to be successfull so need help on the same.
Sample Plunkur for the same:
enter link description here
Thanks in advance.
Basically you need to keep track of ng-model of checkboxes with some property in your $scope. I did this by modifying your $scope.filters and adding selected property inside it, like below.
var filters = [{
label: 'Brand',
name: 'brand',
values: {
Blackberrys: 503,
Arrow: 175,
ParkAvenue: 358
}
}, {
label: 'Color',
name: 'color',
values: {
Black: 100,
Green: 200,
Red: 300
}
}]
function loadFilters() {
$scope.filters = filters.map(function(filter) {
var filter = angular.copy(filter);
for (var key in filter.values) {
filter.values[key] = {
selected: false,
count: filter.values[key]
}
}
return filter;
})
}
loadFilters();
Then you can call loadFilters() any time you want to clear all filters. Please see POC attached below.
https://plnkr.co/edit/SADPoUpftnJkg1rMuSB9?p=preview
You should try 'ng-change' on checkboxes to trigger a method which changes the values according to checked and unchecked checkboxes.
For Ex.
<input type="checkbox" ng-model='isSelected' ng-click='checkItem(key, k, isSelected)' ng-change="yourMethodHere()">
in JS:
$scope.yourMethodHere = function() {
if (isSelected) {
// filter the values here
} else {
// non filtered values
}
}
By doing this you do not need to even maintain the values of exiting checked/unchecked checkbox.

Clicking a checkbox with protractor?

HTML code
<div class="check-box-panel">
<!--
ngRepeat: employee in employees
-->
<div class="ng-scope" ng-repeat="employee in employees">
<div class="action-checkbox ng-binding">
<input id="John" type="checkbox" ng-click="toggleSelection(employee.name)"
ng-checked="selection.indexOf(employee.name) > -1" value="John"></input>
<label for="John">
::before
</label>
<!--
John
end ngRepeat: employee in employees
-->
<div class="ng-scope" ng-repeat="employee in employees">
<div class="action-checkbox ng-binding">
<input id="Jessie" type="checkbox" ng-click="toggleSelection(employee.name)"
ng-checked="selection.indexOf(employee.name) > -1" value="Jessie"></input>
<label for="Jessie"></label>
I tried using jQuery
element(by.repeater('employee in employees')).element(by.id('Jessie')).click();
also,I tried using css
element(by.repeater('employee in employees')).$('[value="Jessie"]').click();
But it didn't do the job. Any other way I can click on the particular Checkbox?
Alright I had a very similar issue where I couldn't click the checkbox. It turned out I had to click the checkbox label. However if you want to do any checks on if the checkbox is selected then you have to check the actual checkbox. I ended up making two variables, one for the label and one for the actual checkbox.
JessieChkbxLabel = element(by.css("label[for='Jessie']"));
JohnChkbxLabel = element(by.css("label[for='John']"));
//Click the Jessie checkbox
JessieChkbxLabel.click();
//Click the John checkbox
JohnChkbxLabel.click();
You should just need to use element(by.id('Jessie')) to grab your object. The issue you might be having is that click() returns a promise, so you need to handle that with a .then. So something along the lines of:
element(by.id('Jessie')).click().then(function(value) {
// fulfillment
}, function(reason) {
// rejection
});
Aside from checking the id directly, you can also filter the desired element checking the employee name:
var employee = element.all(by.repeater('employee in employees')).filter(function (elm) {
return elm.evaluate("employee.name").then(function (name) {
return name === "Jessie";
});
}).first();
employee.element(by.css("input[type=checkbox]")).click();

How to dynamically generate DOM with Angular.js?

I'm getting started with Angular.js and I'm wondering how to do something along the lines of this (pseudocode):
<li ng-repeat="item in items">
<# if(item.dataType == "string") { #>
<input type="text" />
<# } else if(...) { #>
<input type="password" />
<# } #>
</li>
I know the above code is not angularish, and I know that for simple processing I could use a conditional ng-hide or ng-show or something similar. But for complex behavior, if I had to perform various data checks and business logic, how could I dynamically generate DOM elements with Angular.js?
Within the angular world, DOM manipulation is accomplished using angularjs directives. Here is the angular documentation on directives: https://docs.angularjs.org/guide/directive, you would do well to read through this.
Here is some sample code that will accomplish the idea of your psuedo code:
var myApp = angular.module('myApp', []);
myApp.controller('MyController', function ($scope){
$scope.items = [
42, "hello, world!", 3.14, "i'm alive!"
]
});
myApp.directive('myInputDirective', function () {
return {
restrict: 'E',
replace: true,
template: '<div></div>',
link: function (scope, element, attrs) {
if (typeof scope.current === "string") {
element.append('<input type="text">');
} else {
element.append('<input type="password">');
}
}
}
});
and here's how the html would look:
<div ng-controller="MyController">
<ul ng-repeat="item in items" ng-init="current = item">
<my-input-directive></my-input-directive>
</ul>
</div>
Here is a plnkr with the working example: http://plnkr.co/edit/iiS4G2Bsfwjsl6ThNrnS?p=preview
Directives are how the DOM is manipulated in angular. First thing to notice is that angular has a set of directives that come out of the box, we're using a few above (ng-repeat, ng-init, ng-controller). Above we've created a custom directive that will analyze the data type of each item in the items array of our MyController controller, and append the correct html element.
I imagine that you already understand the ng-repeat directive, so I'll skip that. I'll explain what I'm doing with the ng-init directive though. The ng-init directive allows you to evaluate an expression in the current scope. What this means is that we can write an expression that is evaluated in our current controllers scope, in this case the MyController scope. I am using this directive to create an alias for our current item named current. We can use this inside our directive to check what type the current item in the array iteration is.
Our directive myInputDirective, is returning an object with a few different properties. I won't explain them all here (I'll let you read the documentation), but I will explain what the link function is and what I am doing with it. A link function is typically how we modify the DOM. The link function takes in the current scope (in this case the scope of MyController), a jqLite wrapped element that is associated with the directive, and the attrs which is a hash object with key-value pairs of normalized attribute names and values. In our case, the important parameters are the scope, which contains our current variable, and the element, which we will append the correct input onto. In our link function, we're checking the typeof our current item from our items array, then we are appending an element onto our root element based on what the type of the current item is.
For this particular problem, what I'm doing above is overkill. But based off of your question I figured you were looking for a starting point for more advanced uses of angular apart from the built in directives that angular provides. These are somewhat advanced topics in angular, so I hope that what I've said make some sense. Check out the plunker and play around with it a bit, and go through some of the tutorials on https://docs.angularjs.org/guide. Hope this helps!
You can use ng-show to conditionally hide and show elements e.g.:
<input ng-show="item.dataType === 'string'" type="text"/>
<input ng-show="..." type="password"/>
Assuming your object looks like this:
$scope.items = [
{
dataType: 'string',
value: 'André Pena'
},
{
dataType: 'password',
value: '1234'
},
{
dataType: 'check',
value: true
}
];
Option #1 - ng-switch plunker
<body ng-controller="MainCtrl">
<ul>
<li ng-repeat="item in items">
<div ng-switch="item.dataType">
<div ng-switch-when="string" ><input type="text" ng-model="item.value" /></div>
<div ng-switch-when="password" ><input type="password" ng-model="item.value" /></div>
<div ng-switch-when="check" ><input type="checkbox" ng-model="item.value" /></div>
</div>
</li>
</ul>
</body>
Option #2 - ng-show plunker
<body ng-controller="MainCtrl">
<ul>
<li ng-repeat="item in items">
<div ng-show="item.dataType == 'string'" ><input type="text" ng-model="item.value" /></div>
<div ng-show="item.dataType == 'password'" ><input type="password" ng-model="item.value" /></div>
<div ng-show="item.dataType == 'check'" ><input type="checkbox" ng-model="item.value" /></div>
</li>
</ul>
</body>
Option #3 - ng-hide plunker
<body ng-controller="MainCtrl">
<ul>
<li ng-repeat="item in items">
<div ng-hide="!(item.dataType == 'string')" ><input type="text" ng-model="item.value" /></div>
<div ng-hide="!(item.dataType == 'password')" ><input type="password" ng-model="item.value" /></div>
<div ng-hide="!(item.dataType == 'check')" ><input type="checkbox" ng-model="item.value" /></div>
</li>
</ul>
</body>
You should use the ng-if directive.
<input ng-if="item.dataType === 'string'" type="text"/>
<input ng-if="..." type="password"/>
The problem with using ng-show like #rob suggested, is that it only uses CSS to hide the element, which is not ideal if you want the two inputs to have the same name/ID.
ng-if will remove the element from the DOM if the condition is not true.
for a problem this simple there's no need to go and implement your own directive.

How can a data-bind to an element within a Kendo-Knockout listview?

I have a rather sophisticated template for Kendo ListView using knockout-kendo.js bindings. It displays beautifully. My problem is that I need to use the visible and click bindings in parts of the template, but I can't get them to work. Below is a simplified version of my template. Basically, deleteButtonVisible determines whether the close button can be seen, and removeComp removes the item from the array.
<div class='template'>
<div >
<div style='display:inline-block' data-bind='visible: deleteButtonVisible, event: {click: $parent.removeComp}'>
<img src='../../../Img/dialog_close.png'></img>
</div>
<div class='embolden'>#= type#</div><div class='label1'> #= marketArea# </div>
<div class='label2'> #= address# </div>
<!-- more of the same -->
</div>
The view model:
function CompViewModel() {
var self = this;
self.compData = ko.observableArray().subscribeTo("compData");
self.template = kendo.template(//template in here);
self.removeComp = function (comp) {
//do something here
}
}
html:
<div class="row" >
<div class="col-md-12 centerouter" id="compDiv" >
<div class="centerinner" id="compListView" data-bind="kendoListView: {data: compData, template: template}"></div>
</div>
</div>
finally, sample data:
{
type: "Comparable",
marketArea: "",
address: "2327 Bristol St",
deleteButtonVisible: true
},
Take in count that the deleteButtonVisible must be a property on the viewModel linked to the view.You are not doing that right now. The click element can v¡be access from the outer scope of the binding and remove the $parent.He take the method from the viewmodel. Take in count that every thing that you take on the vie must be present on the view model for a easy access.

Getting value from input control using jQuery

I am using the teleriks treeview control (asp.net mvc extensions), where I may have up to three children nodes, like so (drumroll...... awesome diagram below):
it has its own formatting, looking a bit like this:
<%=
Html.Telerik().TreeView()
.Name("TreeView")
.BindTo(Model, mappings =>
{
mappings.For<Node1>(binding => binding
.ItemDataBound((item, Node1) =>
{
item.Text = Node1.Property1;
item.Value = Node1.ID.ToString();
})
.Children(Node1 => Node1.AssocProperty));
mappings.For<Node2>(binding => binding
.ItemDataBound((item, Node2) =>
{
item.Text = Node2.Property1;
item.Value = Node2.ID.ToString();
})
.Children(Node2 => Node2.AssocProperty));
mappings.For<Node3>(binding => binding
.ItemDataBound((item, Node3) =>
{
item.Text = Node3.Property1;
item.Value = Node3.ID.ToString();
}));
})
%>
which causes it to render like this. I find it unsual that when I set the value it is rendered in a hidden input ? But anyway:...
<li class="t-item">
<div class="t-mid">
<span class="t-icon t-plus"></span>
<span class="t-in">Node 1</span>
<input class="t-input" name="itemValue" type="hidden" value="6" /></div>
<ul class="t-group" style="display:none">
<li class="t-item t-last">
<div class="t-top t-bot">
<span class="t-icon t-plus"></span>
<span class="t-in">Node 1.1</span>
<input class="t-input" name="itemValue" type="hidden" value="207" />
</div>
<ul class="t-group" style="display:none">
<li class="t-item">
<div class="t-top">
<span class="t-in">Node 1.1.1</span>
<input class="t-input" name="itemValue" type="hidden" value="1452" />
</div>
</li>
<li class="t-item t-last">
<div class="t-bot">
<span class="t-in">Node 1.1.2</span>
<input class="t-input" name="itemValue" type="hidden" value="1453" />
</div>
</li>
</ul>
</li>
</ul>
What I am doing is updating a div after the user clicks on a certain node. But when the user clicks on a node, I want to send the ID not the Node text property. Which means I have to get it out of the value in these type lines <input class="t-input" name="itemValue" type="hidden" value="1453" />, but it can be nested differently each time, so the existing code I ahve doesn't ALWAYS work:
<script type="text/javascript">
function TreeView_onSelect(e) {
//`this` is the DOM element of the treeview
var treeview = $(this).data('tTreeView');
var nodeElement = e.item;
var id = e.item.children[0].children[2].value;
...
</script>
So based on that, what is a better way to get the appropriate id each time with javascript/jquery?
edit:
Sorry to clarify a few things
1) Yes, I am handling clicks to the lis of the tree & want to find the value of the nested hidden input field. As you can see, from the telerik code, setting item.Value = Node2.ID.ToString(); caused it to render in a hidden input field.
I am responding to clicks anywhere in the tree, therefore I cannot use my existing code, which relied on a set relationship (it would work for first nodes (Node 1) not for anything nested below)
What I want is, whenever there is something like this, representing a node, which is then clicked:
<li class="t-item t-last">
<div class="t-bot">
<span class="t-in">Node 1.1.2</span>
<input class="t-input" name="itemValue" type="hidden" value="1453" />
</div>
</li>
I want the ID value out of the input, in this case 1453.
Hope this now makes a lot more sense.
if possible would love to extend this to also store in a variable how nested the element that is clicked is, i.e. if Node 1.1.2 is clicked return 2, Node 1.1 return 1 and node 1 returns 0
It's a little unclear what you're asking, but based on your snippet of JavaScript, I'm guessing that you're handling clicks to the lis of the tree & want to find the value of the nested hidden field? If so, you want something like this:
function TreeView_onSelect(e) {
var id = $(e.item).find(".t-input:first").val();
}
Edit: In answer to your follow-up question, you should be able to get the tree depth with the following:
var depth = $(e.item).parents(".t-item").length;
In jQuery you can return any form element value using .val();
$(this).val(); // would return value of the 'this' element.
I'm not sure why you are using the same hidden input field name "itemValue", but if you can give a little more clarity about what you are asking I'm sure it's not too difficult.
$('.t-input').live('change',function(){
var ID_in_question=$(this).val();
});

Categories

Resources