Knockout. Print two properties of an object in a foreach statement - html

I have an observableArray property self.FilteredStudents, the students have name and lastname, and i want to print it together.
Here is the foreach code in the HTML:
<div class="row justify-content-center" data-bind="foreach: FilteredStudents">
<div class="col-md-6 col-lg-4">
<div>
<div class="LLUserCard">
<div class="LLUserCardHeader">
<div>$name $lastName</div>
<div></div>
</div>
<div class="LLUserCardBody">
</div>
<div class="LLUserCardFooter">
$enrollmentDate
</div>
</div>
</div>
</div>
</div>
Obviously the code above is not working, the pseudocode <div>$name $lastName</div> is just to specify what i am looking for.
In all the examples or tutorials i've found they use two elements like <td data-bind="text: name"></td><td data-bind="text: lastName"></td> but i don't want to print the values in different elements, i want them to be the text of one element.
Thank you.

you can use a computed or pure computed function or an inline function on the text binding https://jsfiddle.net/0o89pmju/69/
html
<p>
<span data-bind="text: Name"></span>
</p>
<p>
Or
</p>
<span data-bind="text: (firstname() + ' ' + lastname() )"></span>
js
function viewModel() {
var self = this;
this.firstname = ko.observable('bob');
this.lastname = ko.observable('smith');
self.Name = ko.pureComputed(function () {
return self.firstname() + ' ' + self.lastname()
},this);
}
var vm = new viewModel();
(function($) {
ko.applyBindings(vm); //bind the knockout model
})(jQuery);

Related

how to get span text from inner tags using jQuery

I want to get the span text using jQuery so my html code is like below
Note :- actually this logic was in table data so I given example code only.
<div class="strategiesddata">
<div class="strattabletodivmobright">
<p class="stategybuysellchkbox clearfix">
<span class="BUY active" name="spbuy">B</span>
<span class="SELL " name="spsell">S</span>
</p></div>
<div class="strattabletodivmobright">
<p class="stategybuysellchkbox clearfix">
<span class="BUY " name="spbuy">B</span>
<span class="SELL active" name="spsell">S</span>
</p></div>
</div>
In the above html code I have two active, buy or sell div's so my query is if it active span then I should take that span text
ex:- From first div B and next div S text I should take
For this I have written jQuery like this
$(".strategiesddata").each(function () {
t = $(this);
var tst = t.find(".stategybuysellchkbox").closest(".active").html();
});
And
$(".strategiesddata").each(function () {
t = $(this);
var tst = t.closest(".stategybuysellchkbox").find("span[.active]").html();
});
But I'm getting the value is undefined Suggest me where I did the mistake and how to achieve this?
Your jQuery statement is wrong, try this.
var tst = $(".stategybuysellchkbox").find(".active").text();
To reference the elements in question, you should be able to simply use
$(".stategybuysellchkbox span.active")
One issue here is that jQuery's methods like text() and html() will only get you the contents of the first element in the collection.
To get an array of all the text, use .map()
const activeText = $(".stategybuysellchkbox span.active")
.map((_, span) => span.textContent).get();
console.log(activeText);
.active { color: red; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.slim.min.js"></script>
<div class="strattabletodivmobright">
<p class="stategybuysellchkbox clearfix">
<span class="BUY active" name="spbuy">B</span>
<span class="SELL " name="spsell">S</span>
</p></div>
<div class="strattabletodivmobright">
<p class="stategybuysellchkbox clearfix">
<span class="BUY " name="spbuy">B</span>
<span class="SELL active" name="spsell">S</span>
</p></div>
You definitely don't need jQuery for this either
const activeText = Array.from(
document.querySelectorAll(".stategybuysellchkbox span.active"),
(span) => span.textContent
);

jquery multiple selectors in single query

I have various lists and inside those lists I've list of checkboxes and I've show more/less functionality.
Now, everything works fine but I want to convert some logic to one liner, tried various ways but didn't work so posting here.
Here is HTML part, and assume I have multiple lists like this.
<div id="list-special-needs">
<h4 class="filter-header">Special Needs</h4>
#foreach (var item in specialNeeds)
{
<div class="am-checkbox" style="padding: 3px 0;">
<input id="chk-special-needs-#item.ToLower()" name="special-needs" value="#item" type="checkbox" class="schedulerepeat-checkbox" onclick="return prepareSearchParams()" />
<label for="chk-special-needs-#item.ToLower()" class="margin-h-10 mobile-padding">#item</label>
</div>
}
<p onclick="return loadMore(this, 'list-special-needs', '#specialNeeds.Length')" class="show-more">Show more...</p>
</div>
<div class="clearfix"></div>
Js:
<script type="text/javascript">
PageEvent.add(PageEvent.AFTER_INIT, function () {
$("#list-services .am-checkbox").slice(5).hide();
$("#list-timing .am-checkbox").slice(5).hide();
$("#list-special-needs .am-checkbox").slice(5).hide();
$("#list-neighborhoods .am-checkbox").slice(5).hide();
});
function loadMore(element, listId, length) {
var listSelector = $(`#${listId} .am-checkbox`);
var isShowMore = $(element).text() == 'Show more...';
if (isShowMore) {
//..show more
$(element).text('Hide...');
listSelector.slice(0, length).slideDown();
} else {
//..hide
$(element).text('Show more...');
listSelector.slice(5).slideUp();
}
}
</script>
and I just want to convert this into one liner.
$("#list-services .am-checkbox").slice(5).hide();
$("#list-timing .am-checkbox").slice(5).hide();
$("#list-special-needs .am-checkbox").slice(5).hide();
$("#list-neighborhoods .am-checkbox").slice(5).hide();
Although I tried this, but it didn't work.
$("#list-services .am-checkbox, #list-timing .am-checkbox ..").slice(5).hide();
Any help would be really appreciated.
You should work with each one of them separately. So from your code:
$("#list-services .am-checkbox, #list-timing .am-checkbox ..").slice(5).hide();
We can take that and loop through and attack each one with
Array.from($("#list-services .am-checkbox, #list-timing .am-checkbox ..")).forEach(elem => {elem.slice(5).hide());
Although I'd suggest adding a class to each one of the blocks with te list-... IDs, so the code is nicer and go with:
Array.from($(".list-block .am-checkbox")).forEach(elem => {elem.slice(5).hide());
Create array of your elements with id's, then for each search for that same class and do stuff...
[...$("#list-services"), ...$("#list-timing"), ...$("#list-special-needs"), ...$("#list-neighborhoods")].forEach(el => {
$(el).find(".am-checkbox").slice(5).hide()
})
"need something more elegant"
Beauty is in eye of the beholder, is this one pretty enough?
[...document.querySelectorAll("#list-services, #list-timing, #list-special-needs, #list-neighborhoods")].forEach(el => $(el).find(".am-checkbox").slice(5).hide())
[...document.querySelectorAll("#list-services, #list-timing, #list-special-needs, #list-neighborhoods")].forEach(el => $(el).find(".am-checkbox").css("color", "red"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="list-services">
<div class="am-checkbox">1</div>
</div>
<div id="list-timing">
<div class="am-checkbox">2</div>
</div>
<div id="list-special-needs">
<div class="am-checkbox">3</div>
</div>
<div id="list-neighborhoods">
<div class="am-checkbox">4</div>
</div>

Is it possible to create a sort of HTML object (even using a framework)

I was wondering if it was possible to create a sort of HTML object instead of copy pasting stuff, I thought of doing it via javascript but wondered if there was an easier way to do it (writing html in JS is a bit tedious).
Basically let's say a have a div like that:
<div class ="col">
<div class="Title">
Title
</div>
<div class="Text">
Text
</div>
</div>
Which is the best way, to have some sort of function where you can objectName.create(title, text) or to have a javascript function like Function(title, text) create the element?
You could take the outer element and clone it, change its content and append it back to where you want it. Be advised that this may duplicate ids if your elements should have one.
function createHtml(title, text) {
const el = document.querySelector('.col').cloneNode(true);
el.querySelector('.Title').innerText = title;
el.querySelector('.Text').innerText = text;
document.body.appendChild(el);
}
createHtml("Foo", "Bar");
<div class="col">
<div class="Title">
Title
</div>
<div class="Text">
Text
</div>
</div>
Another option would be to create the element from scratch
function createElement(title, text) {
const el = document.createElement('div');
el.clasName = 'col';
const titleDiv = document.createElement('div');
titleDiv.className = 'Title';
titleDiv.appendChild(document.createTextNode(title));
const textDiv = document.createElement('div');
textDiv.className = 'Text';
textDiv.appendChild(document.createTextNode(text));
el.appendChild(titleDiv);
el.appendChild(textDiv);
document.body.appendChild(el);
}
createElement("Foo", "Bar");
Note that there are many frameworks out there (like angular, react, vue, ...) that would do things like that easier/better.
It is not so bad to write html in js after template literals became a thing in js, you could do something like this
function addCol(title, text){
document.querySelector(".list").innerHTML += `
<div class="col">
<div class="Title">
${title}
</div>
<div class="Text">
${text}
</div>
</div>
`;
}
addCol("hello", "world");
addCol("foo", "bar");
<div class="list"></div>

Select a node with its children based on its class, and turn it into an object

I want to find out how to scrape website data. This is a part of the html that I am interested in. I am using cheerio for finding the data I need.
<td class="col-item-shopdetail">
<div class="shoprate2 text-right hidden-xs">
<div class="currbox-amount">
<span class="item-searchvalue-curr">SGD</span>
<span class="item-searchvalue-rate text-black">42.0000</span>
</div>
<div class="item-inverserate">TWD 100 = SGD 4.2</div>
<div class="rateinfo">
<span class="item-timeframe">12 hours ago</span>
</div>
</div>
<div class="shopdetail text-left">
<div class="item-shop">Al-Aman Exchange</div>
<div class="item-shoplocation">
<span class="item-location1"><span class="icon icon-location3"></span>Bedok</span>
<span class="item-location2"><span class="icon iconfa-train"></span>Bedok </span>
</div>
</div>
</td>
I wish to make "col-item-shopdetail" class as an object and store all class with name "col-item-shopdetail" into an array for access.
So if possible, it will be access like array.item-inverserate or through cheerio selector like
$('.col-item.shopdetail').children[0].children[0].children[1]
I have tried looping through the names of shop and store in an array and use another loop after finish looping the names to find the rates. Then try and match the rates to the name by access same index of the array. However this did not work for unknown reason where each time the rate printed is of different value and index of the same name are different in each try.
This is close to what I want but it does not work:
how to filter cheerio objects in `each` with selector?
In other words, you want an array of objects representing elements having class .col-item-shopdetail and each of those objects should have a property corresponding to the .item-inverserate element they contain ?
You need the map method
my_array = $('.col-item-shopdetail').map(function(i, el) {
// Build an object having only one property being the .item-inverserate text content
return {
itemInverserate: $(el).find('.item-inverserate').text()
};
}).get();
// You can also directly target inverserate nodes
// which will exclude empty entries ('shopdetail' that have no 'inverserate')
// Loop over .item-inverserate elements found
// somewhere in a .col-item-shopdetail
// (beware, space matters)
my_array = $('.col-item-shopdetail .item-inverserate').map(function(i, el) {
// Build an object having only one property being the .item-inverserate text content
return {itemInverserate: $(el).text()};
// Note: If all you need is the inverserate value,
// Why not avoiding an intermediate full object?
// return $(el).text()
}).get();
Since Cheerio developers have built their API based on jQuery with most of the core methods, we can simply test snippets in the browser ...
my_array = $('.col-item-shopdetail').map(function(i, el) {
return {
itemInverserate: $(el).find('.item-inverserate').text()
};
}).get();
console.log(my_array[0].itemInverserate)
my_array_2 = $('.col-item-shopdetail .item-inverserate').map(function(i, el) {
// Build an object having only one property being the .item-inverserate text content
return {itemInverserate: $(el).text()};
}).get();
console.log(my_array_2[0].itemInverserate)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table><tr><td class="col-item-shopdetail">
<div class="shoprate2 text-right hidden-xs">
<div class="currbox-amount">
<span class="item-searchvalue-curr">SGD</span>
<span class="item-searchvalue-rate text-black">42.0000</span>
</div>
<div class="item-inverserate">TWD 100 = SGD 4.2</div>
<div class="rateinfo">
<span class="item-timeframe">12 hours ago</span>
</div>
</div>
<div class="shopdetail text-left">
<div class="item-shop">Al-Aman Exchange</div>
<div class="item-shoplocation">
<span class="item-location1"><span class="icon icon-location3"></span>Bedok</span>
<span class="item-location2"><span class="icon iconfa-train"></span>Bedok </span>
</div>
</div>
</td></tr>
</table>

passing html values to javascript functions

I have a ng-repeat in my view and I want to pass the object from my ng-repeat to a javascript function but when I try to display it on the console it gives me undefined.
Here is my html:
<!-- Panel -->
<div class="row">
<div class="col-lg-12">
<div class="panel panel-primary">
<div class="panel-heading">
{{card}}
</div>
<!-- /.panel-heading -->
<div class="panel-body">
<div id="nvd3-container" class="md-card" style="overflow-x: auto" ng-if="dataloaded0">
<md-card-content id="nvd3-scrollable-content" style="width: {{width}}px; height: 350px;">
<md-tabs md-dynamic-height="" md-border-bottom="">
<md-tab ng-repeat="pu in selectedKpi" label="{{pu.dprdProuNr}}">
<md-content class="md-padding">
<div class="row">
<div class="col-md-6">
{{pu.item1}}
{{pu.item2}}
</div>
</div>
</md-content>
</md-tab>
</md-tabs>
</md-card-content>
</div>
</div>
<!-- /.panel-body -->
<a href="" ng-click="footerLinkClicked(pu)">
<div class="panel-footer">
<span class="pull-left">Trend</span>
<span
class="pull-right">
<i class="fa fa-arrow-circle-right"></i>
</span>
<div class="clearfix"></div>
</div>
</a>
</div>
</div>
</div>
<!-- /.panel -->
Here is my js file that returns undefined:
angular.module('App')
.directive('KpiParameter', function() {
return {
restrict: 'E',
templateUrl: 'app/kpi/kpi-parameter/kpi-parameter.html',
scope: {
card: '=',
kpiParamCallback: '&',
selectedProductionUnit: '<'
},
controller: function($scope, $rootScope, KpiChartFactory, $filter) {
console.log("!???????");
console.log($scope.selectedProductionUnit);
$scope.$watch('selectedProductionUnit', function() {
console.log($scope.selectedProductionUnit);
console.log("Changed");
KpiParamUpdated();
$scope.kpiParamCallback({
selectedProductionUnit: $scope.productionUnitDefault
});
}, true);
function KpiParamUpdated() {
console.log("KPiParamUpdated");
console.log($scope.selectedProductionUnit);
$scope.dataloaded0 = true;
KpiChartFactory.get({ pu: $scope.selectedProductionUnit }, function(data) {
$scope.selectedKpi = data;
console.log($scope.selectedKpi);
$rootScope.$broadcast('kpiParams', $scope.selectedKpi);
});
}
$scope.footerLinkClicked = function(pu) {
console.log("parameters received :");
console.log(pu);
}
},
controllerAs: "KpiPCtrl"
};
});
Do you have any idea why? I need to define it also in my js file?
As found in the docs of AngularMaterial, you can only achieve what you want to do by using md-on-select
Attributes
Parameter Type Description
label string
Optional attribute to specify a simple string as the tab label
ng-disabled boolean If present and expression evaluates to truthy, disabled tab selection.
md-on-deselect expression Expression to be evaluated after the tab has been de-selected.
md-on-select expression Expression to be evaluated after the tab has been selected.
md-active boolean When true, sets the active tab. Note: There can only be one active tab at a time.
Note: This event differs slightly from ng-click, in that if a tab is already selected and then clicked, the event will not fire.
Your call to footerLinkClicked() has no way of knowing which pu to use unless you tell it which one to use. And since it's outside of your ng-repeat, there's no overly easy way to do that.
md-tabs has an attribute called md-selected that allows you to store the currently selected index in a variable. So assuming that selectedKpi is an array (or is array-like), you can do this:
<md-tabs md-dynamic-height="" md-border-bottom="" md-selected="selectedTab">
and this:
<a href="" ng-click="footerLinkClicked(selectedKpi[selectedTab])">
and you should be all set.