So, just a little background ... I need to process data in my controller with data that is coming from the Client side. Thus, knockout.js was suggested.
This particular page has a main page, and then multiple placeholders which all have the same format. The main issue is that only one of these is appearing, and that happens to be the last one. When I inspect element, I see the data present, but not rendered.
here is the code:
First ... the markup for the parent item.
#using (Html.BeginFooterScripts())
{
<script type="text/javascript" src="//ajax.aspnetcdn.com/ajax/knockout/knockout-3.3.0.js"></script>
<script type="text/javascript" src="/Content/Northwestern/js/_libs/knockout.mapping/knockout.mapping.2.4.1.js"></script>
<script type="text/javascript" src="~/Content/Northwestern/js/views/TabPanel/location-card.js"></script>
<script type="text/javascript">
var once = true;
$(function () {
if (once) {
initialize();
once = false;
}
});
</script>
}
<div class="resp-tabs-container tabs-narrow">
#if (Model.TabSelector.Equals("location-row"))
{
<div>
#*this div needs to be empty. The easyResponsiveTabs plugin adds classes to it and matches it with the <li> in the resp-tab-list above*#
#*Location List *#
<div class="#Model.TabSelector">
<div class="indent">
<h3>#Model.Title</h3>
</div>
#Html.Sitecore().DynamicPlaceholder("Location-Card")
</div>
</div>
}
The DynamicPlaceholder is where the problem is ... currently there are 9 identical Location-Cards
Here is the markup for the LocationCard.cshtml
#using (Html.BeginFooterScripts())
{
<script type="text/javascript" src="~/Content/Northwestern/js/views/TabPanel/location-card.js"></script>
<script>
$(function() {
geoLocate(function(location) {
var latitude = location.coords.latitude;
var longitude = location.coords.longitude;
displayLocation('#Model.LocationId', latitude, longitude);
});
});
</script>
}
<div id="detail-container">
</div>
<script type="text/html" id="location-detail-template">
<h2 class="location-title" itemprop="name" data-bind="text: ItemName">#Model.Location.ItemName</h2>
</div>
<div class="distance">
<i class="material-icons">place</i> <span data-bind="text: Distance.toFixed(1)"> Mi</span>
</div>
<div class="location-phone">
<a data-bind="attr: { 'href': clickToCallify(Phone), 'data-track-event': 'Find a Location - Detail', 'data-track-action': 'call icon' }" class="tel" itemprop="telephone">#Model.Location.Phone</a>
</div>
</div>
</div>
</script>
</div>
<div class="col lg-6 xl-7">
#(new HtmlString(Model.Body))
</div>
</div>
}
and here is the Location-card.js
var applied = false;
var geoLocateError = function onError(error) {
alert(error.message);
};
function ViewModel() {
var self = this;
self.currentLocation = {
latitude: 0,
longitude: 0
};
}
var viewModel = new ViewModel();
$(function () {
});
function initialize() {
ko.applyBindings(viewModel);
geoLocate(function(location) {
initLocation(location);
}, geoLocateError);
}
/**********************************************
* Location Functions
**********************************************/
function initLocation(location) {
viewModel.currentLocation = {
latitude: location.coords.latitude,
longitude: location.coords.longitude
};
}
function displayLocation(id, lat, lng) {
var apiUrl = '/api/northwestern/locations/getlocationbyid/' + id;
var data = {
'latitude': lat,
'longitude': lng
};
self.LocationId = id;
$.getJSON(apiUrl, data, function (response) {
var fragment = document.createDocumentFragment(),
container = document.createElement('div'),
viewModel = response;
fragment.appendChild(container);
// merge together all the display types into a commma-separated list
response.TypeListDisplay = $.map(response.Types, function (obj, t) {
return obj.ItemName;
}).join(', ');
ko.renderTemplate(
"location-detail-template",
viewModel, {
afterRender: function () {
$('#detail-container').html(container.innerHTML);
}
},
container
);
});
}
So, I am not certain what to do. I have been working on this now for several days
any help would be appreciated.
Related
<div id="SearchAddress">
<div class="main_class">
<div class="find_juso_map">
<input type="button" v-on:click="load_juso" value="주소 검색"><br>
<div id="map" style="width:300px;height:300px;margin-top:10px;"></div>
<input type="text" id="sample5_address" placeholder="메모">
<input type="button" v-on:click="add_place" value="장소 추가"><br>
</div>
<div class="set_juso_list">
<h4>요기조아</h4>
<div></div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'SearchAddress',
data() {
return {
center: new window.kakao.maps.LatLng(33.450701, 126.570667),
geocoder: new window.kakao.maps.services.Geocoder(),
joah_add: null,
joah_list: {}
}
},
props: {
},
mounted () {
var container = document.getElementById('map');
var options = {
center: this.center,
level: 3
};
new window.daum.maps.Map(container, options);
},
methods: {
load_juso() {
new window.daum.Postcode({
oncomplete: function(data) {
var addr = data.address; // 최종 주소 변수
console.log(addr,'주소')
this.joah_add = addr;
console.log(this.joah_add ,'조아조아')
// // 주소로 상세 정보를 검색
new window.kakao.maps.services.Geocoder().addressSearch(data.address, function(results, status) {
// 정상적으로 검색이 완료됐으면
if (status === window.daum.maps.services.Status.OK) {
var result = results[0]; //첫번째 결과의 값을 활용
// 해당 주소에 대한 좌표를 받아서
var coords = new window.daum.maps.LatLng(result.y, result.x);
// 지도를 보여준다.
var container = document.getElementById('map');
var map = new window.daum.maps.Map(container, {center: coords,level: 3});
container.style.display = "block";
map.relayout();
map.setCenter(coords);
new window.daum.maps.Marker({position: coords, map: map}).setPosition(coords);
}
});
}
}).open();
},
add_place() {
console.log('장소추가',this.joah_add)
}
}
}
</script>
I want to put joah_add data in the load_juso() and call it in the add_place.
first, I called load_juso() method.
I think, 'this.joah_add = addr;' <- this code can access data and set data: joah_add value.
second, I called add_place method.
why console print joah_add data -> null??
why doesn't it come out like 'this.joah_add = addr'?
please help me :'(
Javascript's this is not bound from the start
but is bound at the time of the call
So your this.joah_add = addr; of this
may be pointing to daum instead of vue
Javascript's this in normal function mode
points to whoever calls it
So
new window.daum.Postcode({... this.joah_add = addr})
could be equivalent to
new window.daum.Postcode({... daum.joah_add = addr})
and not
new window.daum.Postcode({... vue.joah_add = addr})
And your
add_place() {
console.log('장소추가',this.joah_add)
}
should be
add_place() {
console.log('장소추가',vue.joah_add)
}
So here's what you might need to do
load_juso() {
const that = this
new window.daum.Postcode({… that.joah_add = addr;...})
...
}
Hope it can help you
It might be over kill but this works. I copied the first variable in its entirety and and gave it a new name. Also, delinked it from call_files/header.html and css/header.css files. Instead, I linked it to the layout.css which governs the appearance of the second menu. I'm sure there is a way to stream line it.
<script type="text/javascript">
$().ready(function () {
var stickyPanelOptions = {
topPadding: 0,
afterDetachCSSClass: "BoxGlow_Grey2",
savePanelSpace: true,
onDetached: function (detachedPanel, spacerPanel) {
call_files/header.html(call_files/header.html() + " has been detached!");
css/header.css("background-color", "#1000ff");
},
onReAttached: function (detachedPanel) {
call_files/header.html(call_files/header.html().replace(" has been detached!", ""));
},
parentSelector: null
};
var secondstickyPanelOptions = {
topPadding: 150,
savePanelSpace: true,
onDetached: function (detachedPanel, spacerPanel) {
detachedPanel.html(detachedPanel.html() + " has been detached!");
layout.css("background-color", "#ffffff");
},
onReAttached: function (detachedPanel) {
detachedPanel.html(detachedPanel.html().replace(" has been detached!", ""));
},
parentSelector: null
};
// multiple panel example (you could also use the class ".stickypanel" to select both)
$("#Panel1").stickyPanel(stickyPanelOptions);
$("#Panel2").stickyPanel(secondstickyPanelOptions);
$("#Panel3").stickyPanel(stickyPanelOptions);
$("#UnstickPanel3").click(function () {
$("#Panel3").stickyPanel("unstick");
});
stickyPanelOptions.parentSelector = "#AbsoluteDiv";
$("#Panel4").stickyPanel(stickyPanelOptions);
stickyPanelOptions.parentSelector = "#NormalDiv";
$("#Panel5").stickyPanel(stickyPanelOptions);
});
</script>
HTML
<div id="Panel1" class="stickyPanel">
<div class="headerBGdiv"> </div>
<?php include('../call_files/pagesheader.html');?>
</div>
<div id="Panel2" class="stickyPanel">
<div id="navbar2">
<ul id="tabs">
<li>Buyer's Guide</li>
<li>Export Restrictions</li>
<li>Infrared 101</li>
<li>White Pages</li>
<li>Terminology</li>
<li>Newsroom</li>
<li>Gallery</li>
</ul>
</div>
</div>
Try This it uses separate config options for each panel.
<script type="text/javascript">
$().ready(function () {
var stickyPanelOptions = {
topPadding: 0,
savePanelSpace: true,
onDetached: function (detachedPanel, spacerPanel) {
call_files/header.html(call_files/header.html() + " has been detached!");
css/header.css("background-color", "#1000ff");
},
secondStickyPanelOptions = stickyPanelOptions,
onReAttached: function (detachedPanel) {
call_files/header.html(call_files/header.html().replace(" has been detached!", ""));
},
parentSelector: null
};
secondStickyPanelOptions.topPadding = 100;
// multiple panel example (you could also use the class ".stickypanel" to select both)
$("#Panel1").stickyPanel(stickyPanelOptions);
$("#Panel2").stickyPanel(secondStickyPanelOptions);
$("#Panel3").stickyPanel(stickyPanelOptions);
$("#UnstickPanel3").click(function () {
$("#Panel3").stickyPanel("unstick");
});
stickyPanelOptions.parentSelector = "#AbsoluteDiv";
$("#Panel4").stickyPanel(stickyPanelOptions);
stickyPanelOptions.parentSelector = "#NormalDiv";
$("#Panel5").stickyPanel(stickyPanelOptions);
});
</script>
So heres how this works so far,the index page allows you to create a game. Games are then posted onto /data/games ( Gamelist.html). I want to have a button that permanently deletes the games from the list. I currently have a remove button but it doesnt do anything.
Index( create games from here)
<html>
<head>
<title>Planning Poker</title>
<style>
.inlinetext {
display: inline;
}
</style>
<script src="Scripts/jquery-2.1.1.js"></script>
<script src="Scripts/knockout-3.1.0.js"></script>
<script type="text/javascript">
$(function () {
$('#button').on('click', function (data) {
$.post('data/games/create/?title=5', function (d) { console.log(d) });
})
});
</script>
</head>
<body>
<h3 class='inlinetext'> Create Game: </h3>
<input type="text" id="testtext" name="ime">
<button id="button" >Create</button>
</body>
</html>
Controller
using PlanningPoker.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
namespace PlanningPoker.Controllers
{
public class GMController : ApiController
{
private static List<Game> games = new List<Game>() {
new Game() {
ID = Guid.NewGuid(),
Title = "D&D"
}
};
[Route("data/games")]
public IEnumerable<Game> GetAllGames() {
return games;
}
[Route("data/games/create"), HttpPost]
public Guid CreateGame(string title) {
Game g = new Game() {
ID = Guid.NewGuid(),
Title = title
};
games.Add(g);
return g.ID;
}
}
}
Gamelist(html)
<title>Game List</title>
<script src="Scripts/jquery-2.1.1.js"></script>
<script src="Scripts/knockout-3.1.0.js"></script>
<script src="Gamelist.js"></script>
</head>
<body>
<h4>Games</h4>
<ul data-bind="foreach: $data.games">
<li>
Game <span data-bind="text: $index"> </span>:
<span data-bind="text: Title"> </span>
Remove
</li>
</ul>
<button data-bind="click: addGame">Add</button>
</body>
</html>
Gamlist (javascript)
function AppViewModel() {
var self = this;
self.games = ko.observableArray([]);
$.getJSON("/data/games", function (d) {
self.games(d);
});
self.addGame = function () {
self.game.push({ name: "Created On " + new Date() });
};
self.removeGame = function () {
self.game.remove(this);
}
}
$(function () {
ko.applyBindings(new AppViewModel());
});
Knockout will automatically pass back the current item as a parameter in the click event binding...
self.removeGame = function(game) {
self.games.remove(game);
}
Is there any javascript library that I can use to serve HTML content? I would like to create a DIV that the content can be dynamically changed.
<div id="header">
<h2>Header here</h2>
</div>
<div id="dynamic-content">
<p>-- Dynamic content here --</p>
</div>
<div id="footer">
<h3>Footer</h3>
</div>
I'm planning to use jQuery for this, just retrieving the HTML markup from the server and then use jQuery's html() function to replace the content of #dynamic-content. I'm just curious if this is practical if the retrived HTML markup is "large", lets say a whole article.
Is there a simple JavaScript templating framework for this? Or can I even use templating JS frameworks for this?
--Helper--
var uiHelper = function () {
var htmls = {};
var getHTML = function (options) {
/// <summary>Returns HTML in a string format</summary>
/// <param name="options" type="object">options{url:The url to the file with the HTML,successCallback:function,errorCallback:function,isAsync:true||false,cache:true|false}</param>
function xhrSuccess() {
if (this.cache) { htmls[this.url] = this.responseText; };
if (this.successCallback) {
this.successCallback.apply(this.responseText, this.arguments);
} else {
return htmls[this.url];
};
};
function xhrError() {
if (this.errorCallback) {
this.errorCallback.apply(this.statusText);
} else {
return this.statusText;
};
};
if (!htmls[options.url]) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", options.url, options.isAsync);
xmlhttp.cache = options.cache || false;
xmlhttp.url = options.url;
xmlhttp.onload = xhrSuccess;
xmlhttp.onerror = xhrError;
xmlhttp.successCallback = options.successCallback || undefined;
xmlhttp.errorCallback = options.errorCallback || undefined;
xmlhttp.send();
} else {
if (options.successCallback) {
options.successCallback.apply(htmls[options.url], this.arguments);
} else {
return htmls[options.url];
};
};
};
return {
getHTML: getHTML
};
}();
--Usage---
uiHelper.getHTML({
url: url, isAsync: true, cache: false, successCallback: function () {
document.getElementById('dynamicContent').innerHTML = this;
}
});
--Your HTML---
<div id="header">
<h2>Header here</h2>
</div>
<div id="dynamic-content">
<p id='dynamicContent'>-- Dynamic content here --</p>
</div>
<div id="footer">
<h3>Footer</h3>
</div>
Well,I recommend you this jquery plugin: jquery.tmpl
github: https://github.com/BorisMoore/jquery-tmpl
this is the introduction:
ppt: http://skilldrick.co.uk/tmpl/
article: http://footyntech.wordpress.com/2013/08/20/simple-javascript-templating-with-jquery-tmpl/
: )
I have this div which displays a letter, but I want to add an if statement of when to show this div based on the following condition:
if usersCount() > 3 then show letter
<div class=" header" id="letter" data-bind="text: Letter">
....
</div>
How could i add the if statement along with the text - expression statement?
data-bind="if: UserCount() > 13 then text:Letter"` ....??
var userViewModel = function (data) {
var _self = this;
_self.Letter = ko.observable(data.Letter);
};
var roleViewModel = function (data) {
var _self = this;
_self.UserCount = ko.observable(data.UserCount);
};
Check out the Visible Binding. You'll want to create a property in you View Model to handle the logic of hiding/showing the div. Here is a JSFiddle to demonstrate.
<div data-bind="visible: shouldShowMessage, text: Letter">
</div>
<script type="text/javascript">
var viewModel = function(){
var self = this;
self.Letter = ko.observable('Hello, World!');
self.UserCount = ko.computed(function() {
return Math.floor((Math.random() * 20) + 1);
});
self.shouldShowMessage = ko.computed(function() {
return (self.UserCount() > 13);
});
};
</script>