knockout $data binding to an HTML element - data-binding

So, suppose I have this viewmodel named people which consists of an array of person object literals, like
[{ name = John, age = 30, sex = male },
{ name = Mike, age = 29, sex = male },
{ name = Anna, age = 28, sex = female }]
And suppose I wanted to data-bind each person to an <li>, like
<ul data-bind="foreach: people">
<li data-bind="text: name"></li>
</ul>
But, is it possible, maybe through data-bind="with: $data", to bind the whole person object to the <li> so, for example, when I click the <li> some other <div> displays the rest of the information, which in this example would be age and sex?
It's like I wanted the <li> to hold the person object data, so I could use it somewhere else.

Generally, you would want to create like a selectedPerson observable at the view model level and then you could do something like:
<ul data-bind="foreach: people">
<li data-bind="click: $parent.selectedPerson">
<span data-bind="text: name"></span>
<div data-bind="visible: $parent.selectedPerson() === $data">
<span data-bind="text: age"></span>
</div>
</li>
</ul>
You could certainly use a link/button around the name, if you like. When you click on it, selectedPerson will be used as the handler and passed the current data as its first argument. Since, selectedPerson is actually an observable, it will populate it with the data as its value.
Otherwise, you could certainly have another area to display the details where you do:
<div data-bind="with: selectedPerson">
....
</div>
Quick fiddle: http://jsfiddle.net/rniemeyer/8dRZ4/

Related

Keep Filter from HttpPost on next page of PaginatedList in ASP.NET Core MVC

I am creating a program in which I have a Database with records I want to filter.
The filter has 4 input type="text" and returns the right records based on the filters I typed.
The problem is, when I click Next Page link (of PaginatedList), the second page has no filters adapted.
It lose the filters I gave. I know I must give asp-route on Next Page link some variable with the data given in filter like Microsoft Tutorial gives currentFilter, but I have 4 filters like this :
Name=x&Phone=y&...
Here is my Controller Code simplyfied :
public async Task<IActionResult> Index( some variables ){
var appusers = from a in _context.AppUsers
select a;
return(return View(await app.PaginatedList<AppUser>.CreateAsync(appusers.AsNoTracking(), pageNumber ?? 1, pageSize));)
}
AND
[HttpPost]
public async Task<IActionResult> Index(string Name, string Phone, string Calls, string Date){
var ap = from c in _context.AppUsers
select c;
Filter The database based on variable values Name,Phone,Calls,Date
return View(await PushNotificationApp.PaginatedList<AppUser>.CreateAsync(ap.AsNoTracking(),
pageNumber?? 1, pageSize));}
Here is the part of Index :
#using (Html.BeginForm("Index", "AppUsers", new { id = "filterForm" }))
{
name="SearchTrips" value="#ViewData["CurrentTrips"]" />
<input id="NameFilterField" type="text" name="Name" />
<input id="PhoneFilterField" type="text" name="Phone" />
<input id="CallsFilterField" type="text" name="Calls" />
<input id="DateFilterField" type="text" pattern="\d{1,2}/\d{1,2}/\d{4}" name="Date" />
<button class="m-3" type="submit" value="submit">Search</button>
}
AND PAGELIST LINK PART :
<div class="p-2 bd-highlight">
<nav aria-label="Page navigation example">
<ul class="pagination">
<li class="page-item">
<a class="page-link MainButton" asp-action="Index"
asp-route-pageNumber="#(Model.PageIndex - 1)"
asp-route-currentFilter="#ViewData["CurrentFilter"]"
class="page-link #prevDisabled">
Previous
</a>
</li>
<li class="page-item">
<a class="page-link MainButton" asp-action="Index"
asp-route-pageNumber="#(Model.PageIndex + 1)"
asp-route-currentFilter="#ViewData["CurrentFilter"]"
Next
</a>
</li>
</ul>
</nav>
</div>
The problem is, when I click Next Page link (of PaginatedList), the second page has no filters adapted. It lose the filters I gave.
You are doing the filter in the Post action, but when you click the Next link, it will go to the Get action which not filter. So, I think you can make the form do a get request and just do the filter in the Get method.
I know I must give asp-route on Next Page link some variable with the data given in filter like Microsoft Tutorial gives currentFilter, but I have 4 filters like this : Name=x&Phone=y&...
4 filters is the same, just give the other filter parameters to the Next link
<a class="page-link MainButton" asp-action="Index"
asp-route-pageNumber="#(Model.PageIndex + 1)"
asp-route-Name="#ViewData["Name"]"
asp-route-Phone="#ViewData["Phone"]"
asp-route-Calls="#ViewData["Calls"]"
asp-route-Date="#ViewData["Date"]"
Next
</a>
why not use a single box to search everything or four search boxes using the method below in the tutorial?
if (!String.IsNullOrEmpty(searchString))
{
students = students.Where(s => s.LastName.Contains(searchString)
|| s.FirstMidName.Contains(searchString));
}

TypeError in angularjs

I am trying to mark some values in a list as font red color and rest default based on some condition.When I am trying to assign a boolean var for the particular data in the list I ma getting "TypeError: Cannot assign to read only property 'match' of 123;
My code s :
angular.forEach($scope.searchResults, function (value, index) {
//populate searchResults
$scope.searchResults[index].name = "ABC";
$scope.searchResults[index].linkedRecords = [];
if(//check some condition){
$scope.searchResults[index].linkedRecords[i] ="123";
$scope.searchResults[index].linkedRecords[i].match=true;
}
});
<tr data-ng-repeat="searchResult in searchResults ">
<td >
<span data-ng-repeat="source in searchResult.linkedRecords" >
<span ng-if="!source.match">{{ source }}</span>
<span ng-if="source.match" style="color: red">{{ source }}</span>
<br>
</span></td>
</tr>
Any idea how can I make this work in html? I need to set something for each item and make those items in the list appear as red.
You're setting the property to have a value of 123 then you are trying to access a property called 'match'.
$scope.searchResults[index].linkedRecords[i] = 123;
At this point the value of $scope.searchResults[index].linkedRecords[i] is 123.
Which means this line:
$scope.searchResults[index].linkedRecords[i].match=true;
Is equivalent to:
(123).match = true;
This won't work, because the Number type is immutable, which means you can't add or modify properties on their immediate object representation.
You may want to wrap or box your number inside an object. Then you can add other properties to that object.
$scope.searchResults[index].linkedRecords[i] = { value: 123, match: true };
Then your HTML would look something like this instead.
<span data-ng-repeat="source in searchResult.linkedRecords" >
<span ng-if="!source.match">{{ source.value }}</span>
<span ng-if="source.match" style="color: red">{{ source.value }}</span>
<br>
</span>

Multiple 'foreach' loops in one knockout JS

I'll start by saying that I am working within the context of DotNetNuke7, which is essentially ASP.net based framework, and that i am fairly new to KO.
I am trying to have one ko viewmodel and have two foreach loops in it. Each loop renders an array which is part of the view model definition like so:
//We build two arrays: one for the users that are in the group
//and one for the users that are not in the group
var nonGroupMembers = $.map(initialData.NonGroupUsers, function (item) { return new Member(item); });
var groupMembers = $.map(initialData.GroupUsers, function (item) { return new Member(item); });
//The members we start with before we added new members
self.SearchTerm = ko.observable('');
self.CircleMembers = ko.observableArray(groupMembers);
self.NonCircleMembers = ko.observableArray(nonGroupMembers);
In the html context (or the asp user control) i placed the following code
<div id="socialDirectory" class="dnnForm dnnMemberDirectory">
<ul id="mdMemberList" class="mdMemberList dnnClear" style="display:none"
data-bind="foreach: { data: NonCircleMembers, afterRender: handleAfterRender },
css: { mdMemberListVisible : Visible }, visible: HasMembers()">
<li class="memberItem">
<div data-bind="visible: $parent.isEven($data)">
<%=MemberItemTemplate %>
</div>
<div data-bind="visible: !$parent.isEven($data)">
<%=MemberAlternateItemTemplate %>
</div>
</li>
</ul>
</div>
<div class="circleDirectory" id="circleDirectory" >
<ul id="cdMembersList" data-bind =" foreach: {data: CircleMembers, afterRender: handleAfterRender}">
<li class="memberItem">
<div class="mdMemberDetails">
<a href="" class="mdMemberImg" data-bind="attr: { title: DisplayName, href: ProfileUrl }">
<span><img data-bind="attr: { src: getProfilePicture(50,50), title: DisplayName }" /></span>
</a>
<ul class="MdMemberInfo">
<li class="mdDisplayName" >
<a href="" title="" class="mdMemberTitle"
data-bind="attr: { title: DisplayName, href: ProfileUrl },
event: { mouseover: $parent.showPopUp }">
<span data-bind="text: DisplayName"></span>
</a>
</li>
<li class="mdTitle"><p><span data-bind="text: Title"></span></p></li>
<li class="mdLocation"><p><span data-bind="text: Location()"></span></p></li>
</ul>
</div>
</li>
</ul>
</div>
Each one of the DIVs which contain the foreach binding loop in them works perfectly well without the other. For instance, the bottom div (id= cdMembersList) will work fine but when I add the upper div with the binding markups it will stop working. The same thing happens vise verse.
Does anybody have a clue why it might happen? Can i not have 2 loops in one view model?
looking forward to solving this mystery.
thanks,
David
Ok, I hate to say it but the answer is very simple as always. I didn't add to my view model the Visible property for
css: { mdMemberListVisible : Visible }
When I created a new script file I simply skipped this property. A few lessons:
You can run more than one loop in one view model.
Always check that you have all the properties defined in the view model.
Also, apparently it helps creating a question on this board since it makes you think clearly about the problem and revisit your actions. I had spent 2 hours chasing this problem before i posted my question, and then it took me 15 minutes to solve it after I posted it.

Get dragged / saved items state back from Sql Server

Ok i saw many post's on how to serialize the value of dragged items to get hash and they tell how to save them. Now the question is how do i persist the dragged items the next time when user log's in using the has value that i got
eg:
<ul class="list">
<li id="id_1">
<div class="item ui-corner-all ui-widget ui-widget-content">
</div>
</li>
<li id="id_2">
<div class="item ui-corner-all ui-widget ui-widget-content">
</div>
</li>
<li id="id_3">
<div class="item ui-corner-all ui-widget ui-widget-content">
</div>
</li>
<li id="id_4">
<div class="item ui-corner-all ui-widget">
</div>
</li>
</ul>
which on serialize will give
"id[]=1&id[]=2&id[]=3&id[]=4"
Now think that i saved it to Sql server database in a single field called SortOrder.
Now how do i get the items to these order again ?
the code to make these sort is below,without which people didn't know which library i had used to sort and serialize
<script type="text/javascript">
$(document).ready(function() {
$(".list li").css("cursor", "move");
$(".list").sortable();
});
</script>
I believe what Brian is saying is that your table should look like this, if they were sorted in ascending order by the user:
ID Sort Order
1 1
2 2
3 3
4 4
If they were sorted in descending order by the user, the table would look like this:
ID Sort Order
1 4
2 3
3 2
4 1
Then, when you query the database, you would do
SELECT [ID], [Sort Order]
FROM [thetable]
ORDER BY [Sort Order]
and the list would be sorted by the server.
You can then just output the data in the order the server code provides it in.
Rather than storing a single field, can you store a SortOrder column with the data? You can update the DB with the new sort order, and when you query data from the DB, order it by the sort order. Otherwise, in code, you must do a programmatic sort ordering of data, querying the data into something, then looping through and copying the data to another array/list that's sorted based on this one field.
HTH.

Saving Dragged Dropped items position on postback in asp.net

Ok I saw many posts on how to serialize the value of dragged items to get hash and they tell how to save them. Now the question is how do I persist the dragged items the next time when user log's in using the has value that I got
eg:
<ul class="list">
<li id="id_1">
<div class="item ui-corner-all ui-widget ui-widget-content">
</div>
</li>
<li id="id_2">
<div class="item ui-corner-all ui-widget ui-widget-content">
</div>
</li>
<li id="id_3">
<div class="item ui-corner-all ui-widget ui-widget-content">
</div>
</li>
<li id="id_4">
<div class="item ui-corner-all ui-widget">
</div>
</li>
</ul>
which on serialize will give
"id[]=1&id[]=2&id[]=3&id[]=4"
Now think that I saved it to Sql server database in a single field called SortOrder.
Now how do I get the items to these order again ?
the code to make these sort is below, without which people didn't know which library I had used to sort and serialize
<script type="text/javascript">
$(document).ready(function() {
$(".list li").css("cursor", "move");
$(".list").sortable();
});
</script>
There are a few options. One option is to do the sorting server-side. You would read out that string in .NET to generate the list, in order, on the fly. Then output it to the browser.
Another option would be output the serialized string as a string variable in javascript. You could then use jQuery to reorder the elements. The problem with this method is that there would probably be a flash where the unordered list would display and then the correctly ordered list would appear.

Resources