Display an array with string list vertically knockoutjs - javascript

I got self.PatrolList = ko.observableArray() which contains:
//value
0: {DateAdd: 'Tuesday, 01 November 2022', sessionList: Array(2)}
1: {DateAdd: 'Wednesday, 02 November 2022', sessionList: Array(4)}
//sessionList value
Array(2)
0: "Patrol_011122168"
1: "Patrol_011122256"
Now, I want to display them. The problem is sessionList value displaying in a string:
View:
<div class="overflow-auto body-overflow" data-bind="foreach:PatrolList">
<div class="timeline-date" data-bind="text: DateAdd"><i class="fa fa-calendar text-success"></i></div>
<ul>
<li class="timeline-content" data-bind="text: sessionList"></li>
</ul>
</div>
How do I split them by (,) and display vertically. What I want to achieve :
Tuesday, 01 November 2022
-Patrol_011122168
-Patrol_011122256

If you use another loop on ul, you can use $data to get the current value.
class ViewModel {
sessionList = [
"Patrol_011122168",
"Patrol_011122256",
]
}
ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<ul data-bind="foreach: sessionList">
<li class="timeline-content" data-bind="text: $data"></li>
</ul>

Found the answer.
I just have to tweak my view a little bit:
<div class="overflow-auto body-overflow" data-bind="foreach:PatrolList">
<div class="timeline-date" data-bind="text: DateAdd"><i class="fa fa-calendar text-success"></i> 28 Dec</div>
<ul data-bind="foreach: $data.sessionList">
<li class="timeline-content" data-bind="text: $data"></li>
</ul>
</div>
Funnily, I got the solution seconds after posting this questions.

Related

How to render a list using JavaScript

Need help.
I have a json file locally and I want to render a list. So that in the future I can add data to the json file and it will automatically appear on the page.
[
{
country: "England",
cities: [
{
wikiLink: "https://en.wikipedia.org/wiki/London",
citiesName: "London",
citiesDescription: "is the capital and largest city of England and the United Kingdom, with a population of just under 9 million",
},
{
wikiLink: "https://en.wikipedia.org/wiki/Liverpool",
citiesName: "Liverpool",
citiesDescription: "Is a city and metropolitan borough in Merseyside",
},
]
},
{
country: "Island",
cities: [
{
wikiLink: "https://en.wikipedia.org/wiki/Reykjav%C3%ADk",
citiesName: "Reykjavík",
citiesDescription: "It is located in southwestern Iceland, on the southern shore of Faxaflói bay.",
},
]
},
]`
I want to get the following code after rendering
<div class="content">
<div class="section">
<h2 class="title">England</h2>
<ul class="list">
<li class="list__item">
<a class="list__link" href="https://en.wikipedia.org/wiki/London" target="_blank">
<span class="gradient__text">London</span>
- is the capital and largest city of England and the United Kingdom, with a population of just under 9 million
</a>
</li>
<li class="list__item">
<a class="list__link" href="https://en.wikipedia.org/wiki/Liverpool" target="_blank">
<span class="gradient__text">Liverpool</span>
- Is a city and metropolitan borough in Merseyside
</a>
</li>
</ul>
</div>
<div class="section">
<h2 class="title">Island</h2>
<ul class="list">
<li class="list__item">
<a class="list__link" href="https://en.wikipedia.org/wiki/Reykjavik" target="_blank">
<span class="gradient__text">Reykjavík</span>
- It is located in southwestern Iceland, on the southern shore of Faxaflói bay.
</a>
</li>
</ul>
</div>
</div>`
This is roughly what I want to get
I can't figure out how to get to the values of cities. Right now my code looks like this:
import { englandData } from "./englandData.js";
import { islandData } from "./islandData.js";
function blockTemplate(block) {
return`
<div class="list__block-item">
<h2 class="list__desc">
${block.country}
</h2>
<ul class="list">
<li class="list__item">
<a class="list__link" href="${block.cities.wikiLink}" target="_blank">
<span class="gradient__text">${block.cities.citiesName}</span> - ${block.cities.citiesDescription}.
</a>
</li>
</ul>
</div>
`
}
document.getElementById("en").innerHTML = `
${englandData.map(blockTemplate).join("")}
`;
document.getElementById("is").innerHTML = `
${islandData.map(blockTemplate).join("")}
`;
You can use AJAX to fetch data from your JSON file and post it in your HTML Code, Ajax it's will give you the possibility to post, delete, update and get the data from your JSON file.
The problem is, you can only use HTML and Javascript to render an existing file: you can't use them to change the file ... or at least not directly. Instead, you have use AJAX (AKA fetch) to send a request to a server, and then that server can change it.
You will need to learn a lot to be able to build such a server yourself, but luckily there is already an NPM package that does what you want. It starts a server, and then your front-end (ie. your HTML/JS) can use fetch to tell it about changes to your data, and it will save those changes in a JSON file on your computer.
Check out: https://www.npmjs.com/package/json-server

Use single observable for multiple rows in table

<div class="tbody" data-bind="foreach: displayItems">
<div class="t-row">
<div class="t-cell">
<div class="manage-location-buttons">
<a href="javascript:void(0)">
<i class="fa fa-pencil" aria-hidden="true" data-bind="toggleClick: $component.openEditPopup"></i> Edit
</a>
<div class="edit-table-popup" data-bind="visible: $component.openEditPopup">
<ul>
<li><a data-hash="#locationmanagement/managelocations/locationediting" data-bind="click: goToTab">Locations</a></li>
<li><a data-hash="#locationmanagement/managelocations/events" data-bind="click: goToTab">Events</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>
It is my sample of custom table.
On Link click I will show edit-table-popup div like popup. Cause I use only one observable openEditPopup for all items, onclick I see popup for each row.
openEditPopup = ko.observable<boolean>(false);
toggleClick - is custom dirrective, which changes boolean value to opposite
Is it possible to use only one observable but to show popup only for clicked row?
Yes, it's possible.
The click binding sends two arguments to an event handler:
The clicked $data,
The click-event.
If your click handler is an observable, this means it calls the observable like so: yourObservable(data, event)
Knowing that an observable is set by calling it with an argument, you can imagine what happens. Note that knockout ignores the second argument.
The solution would therefore be to change the openEditPopup from containing a bool, to containing a displayItem, and changing the visible binding to:
visible: $component.openEditPopup() === $data
An example:
var vm = {
selected: ko.observable("A"),
items: ["A", "B", "C", "D"]
};
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<p>Tabs</p>
<div data-bind="foreach: items">
<span data-bind="text: $data, click: $parent.selected"></span>
</div>
<p>Content</p>
<div data-bind="foreach: items">
<div data-bind="visible: $parent.selected() === $data">
<h1 data-bind="text:$data"></h1>
</div>
</div>
If I understand correctly, all your rows are bound to one observable and so when you click the row it is setting it to true and all pop ups are showing up?
If so, this would suggest you have a popup per row? I'd recommend changing this and having one popup that is toggled per row and then set it's data to the selected row. Something like this can be achieved with the code below.
var viewModel = function() {
var rows = ko.observableArray([
{id: 1, name: "gimble"}, {id: 2, name: "bob"}, {id: 3, name: "jess"}
]);
var selectedRow = ko.observable();
function showRowPopup(row)
{
//console.log(row.id);
if(selectedRow() == row)
selectedRow(null);
else
selectedRow(row);
}
return {
rows: rows,
showRowPopup: showRowPopup,
selectedRow: selectedRow
}
}
ko.applyBindings(new viewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="foreach: rows">
<div>
<span data-bind="text: id"></span> -
<span data-bind="text: name"></span>
<button data-bind="click: $parent.showRowPopup">Toggle Modal</button>
</div>
</div>
<div data-bind="with: selectedRow">
<h3>My Fake Modal</h3>
<span data-bind="text: id"></span> -
<span data-bind="text: name"></span>
</div>

How to replace a default date with an empty string

I have a html span that display a date using moment.js in the page:
<span data-bind="text: moment(new Date(dueDate())).format('MM/DD/YYYY')"></span>
It's working fine apart if the dueDate() property is an empty string, If it's an empty string I'm getting:
01/01/1900
How can avoid that?
This is the entire div:
<div class="col-md-8">
<ul>
<li>DATE <span data-bind="text: moment(new Date(sDate())).format('MM/DD/YYYY')"></span></li>
<li>Due date <span></span><span data-bind="text: moment(new Date(dueDate())).format('MM/DD/YYYY')"></span>
<p>Days Remaining: <span class="days-remaining" data-bind="text: daysRemaining"></span></p>
</li>
<li>Date 2 <span></span><span data-bind="text: moment(new Date(date2())).format('MM/DD/YYYY')"></span>
<p>Days Remaining: <span class="days-remaining" data-bind="text: daysRemaining"></span></p>
</li>
</ul>
</div>
You will have to add a check. If value exists, then parse value, else show blank.
this.getDateInFormat = function(str){
var d = moment(str, DEFAULT_FORMAT);
return str && d.isValid() ? d.format('MM/DD/YYYY') : '';
}
As commented before, you should move all parsing logic to your viewModel. This way your code is generic and your view is clean.
JSFiddle.

Inserting HTML using Jquery (Limiting amount of times)

I am trying to insert a snippet of HTML code after each feed item using JQuery, however whatever I try it still doesn't work. I have displayed the HTML code below of the page I am trying to edit. I am trying to get some HTML to be inserted after every feed time (every time it finishes with class="wp_rss_retriever_container">)
<div class="wp_rss_retriever">
<ul class="wp_rss_retriever_list">
<li class="wp_rss_retriever_item">
<div class="wp_rss_retriever_item_wrapper">
<a class="wp_rss_retriever_title" target="_blank" href="http://footballnewsdaily.net/uncategorized/man-united-ready-to-smash-transfer-record-to-sign-star-striker/" title="Man United ready to smash transfer record to sign star striker">
Man United ready to smash transfer record to sign star striker
</a>
<div class="wp_rss_retriever_container">
<div class="wp_rss_retriever_metadata">
<span class="wp_rss_retriever_date">
Published: March 25, 2016 - 12:29 pm
</span>
</div>
</div>
</div>
</li>
<li class="wp_rss_retriever_item">
<div class="wp_rss_retriever_item_wrapper">
<a class="wp_rss_retriever_title" target="_blank" href="http://footballnewsdaily.net/manchester-united/fenerbahce-plan-bid-for-manchester-united-ace-mata/" title="Fenerbahce plan bid for Manchester United ace Mata">
Fenerbahce plan bid for Manchester United ace Mata
</a>
<div class="wp_rss_retriever_container">
<div class="wp_rss_retriever_metadata">
<span class="wp_rss_retriever_date">
Published: March 25, 2016 - 12:15 pm
</span>
</div>
</div>
</div>
</li>
<li class="wp_rss_retriever_item">
<div class="wp_rss_retriever_item_wrapper">
<a class="wp_rss_retriever_title" target="_blank" href="http://footballnewsdaily.net/manchester-united/united-arsenal-target-morata-premier-league-would-suit-me/" title="Manchester United, Arsenal target Morata: Premier League would suit me">
Manchester United, Arsenal target Morata: Premier League would suit me
</a>
<div class="wp_rss_retriever_container">
<div class="wp_rss_retriever_metadata">
<span class="wp_rss_retriever_date">
Published: March 25, 2016 - 11:55 am
</span>
</div>
</div>
</div>
</li>
<li class="wp_rss_retriever_item">
<div class="wp_rss_retriever_item_wrapper">
<a class="wp_rss_retriever_title" target="_blank" href="http://footballnewsdaily.net/manchester-united/manchester-united-rival-arsenal-liverpool-for-juventus-striker-morata/"
The code i tried to use to get it to work is
$( "<p>Test</p>" ).insertAfter( ".wp_rss_retriever_container" );
You could use each to iterate over all the .wp_rss_retriever_container class:
$('.wp_rss_retriever_container').each(function(i, obj) {
$(this).append("<p>Test</p>"); //or .html()
});
If you want it to be 'limited amount of times' you could condition and break if 'i' is equal to some value:
if(i == 5){ break; } // only 4 'test' will be added
Hope it helps to you!

Click on a link in repeater with Protractor

I have been troubling with finding the way to click on EDIT link under particular item:
<li ng-repeat="item list | orderBy: predicate:false" class="ng-scope">
<h1 class="ng-binding">item name</h1>
<p>
</p><div class="w140 left borderRight ng-binding">
Contains:
</div>
<div class="left marginLeft20 ng-binding">
Last modified:
Dec 5, 2014
</div>
<p></p>
edit
</li>
So I need to find correct item by item name and to click on the edit link. This is what I have so far but it's not finding anything:
element(by.cssContainingText('.ng-binding', 'item name')).
element(by.linkText('edit')).
click();
You are trying to select 'edit' link inside h1 element.
Select 'edit' link inside li element.
element(by.cssContainingText('li', 'item name')).element(by.linkText('edit')).click();
EDIT
Or
element(by.cssContainingText('li', 'item name')).element(by.css('a')).click();

Categories