I have the following HTML
<div id="tabPanelContainer">
<div id="Tab1" data-options="dxItem: { title: 'Tab1' }">
<div id="gridContainer1"></div>
</div>
<div id="Tab2" data-options="dxItem: { title: 'Tab2' }" >
<div id="gridContainer2"></div>
</div>
</div>
I want to create this using js or jquery I have tried the following:
A.
var tabs = $('#tabPanelContainer').data("options","dxItem: { title: "+tabId+" }");
$(tabs).append('<div id='+gridId+'></div>');
B.
var tabs = $('#tabPanelContainer').attr({ 'data-options': 'dxItem: { title: "+tabId+" }' });
$(tabs).append('<div id='+gridId+'></div>');
I have looked at multiple threads on how to do this and tried multiple things but nothing is working....
I have found this: How to set data attributes in HTML elements , and other similar threads but not quite the same or enough to figure it out.
This creates multiple grids but not the tabs. So to be clear if I create the HTML elements on the PHP file (hardcoded) then my tabs load correctly but if I try to dynamically create the tabs based on a for loop my tabs don't get created.
Instead of
You are setting the data attribute of #tabPanelContainer instead of each div element. Use this code instead:
var tabs = $("#tabPanelContainer"); // <div id="tabPanelContainer">
var tab = $("<div>", { id: tabId }); // <div id="Tab1">
tab.attr("data-options", "dxItem: { title: '" + tabId + "' }");
tab.append($("<div>", { id: gridId })); // <div id="gridContainer2">
$(tabs).append(tab);
Related
I included a reusuable navbar on multiple pages and it's working fine but when I tried changing the textContent of a word on same navbar, it shows undefined even when i have already declared the variable. What am I not getting right?
I wish to change the span with the id first_name to the name of the data.first_name in the array and I want it to reflect on every page.
$(function() {
$("#nav-placeholder").load("navbar.html");
var first_name = document.getElementById("first_name");
var data = [{
"first_name": "Chibuogwu"
}]
first_name.innerHTML = data.first_name;
});
<div class="content-side content-side-full text-center bg-black-10">
<div class="smini-hide">
<img class="img-avatar" src="assets/media/photos/avatar0.jpg" alt="">
<div class="mt-2 mb-1 font-w600">
<span id="first_name"> User</span></div>
</div>
</div>
When you use jQuery, use jQuery
Also load is async and data is an array
const data = [{
"first_name": "Chibuogwu"
}]
$(function() {
$("#nav-placeholder").load("navbar.html",function() {
$("#first_name").html(data[0].first_name);
});
});
data is an array so it should be accessed first. Please check below:
first_name.innerHTML = data[0].first_name;
I'm pretty experienced with Knockout but this is my first time using components so I'm really hoping I'm missing something obvious! I'll try and simplify my use case a little to explain my issue.
I have a HTML and JS file called Index. Index.html has the data-bind for the component and Index.js has the ko.components.register call.
Index.html
<div data-bind="component: { name: CurrentComponent }"></div>
Index.js
var vm = require("SectionViewModel");
var CurrentComponent = ko.observable("section");
ko.components.register("section", {
viewModel: vm.SectionViewModel,
template: "<h3>Loading...</h3>"
});
ko.applyBindings();
I then have another HTML and JS file - Section.html and SectionViewModel.js. As you can see above, SectionViewModel is what I specify as the view model for the component.
Section.html
<div>
<span data-bind="text: Section().Name"></span>
</div>
SectionViewModel.js
var SectionViewModel = (function() {
function SectionViewModel() {
this.Section = ko.observable();
$.get("http://apiurl").done(function (data) {
this.Section(new SectionModel(data.Model)); // my data used by the view model
ko.components.get("dashboard", function() {
component.template[0] = data.View; // my html from the api
});
});
}
return SectionViewModel;
});
exports.SectionViewModel = SectionViewModel;
As part of the constructor in SectionViewModel, I make a call to my API to get all the data needed to populate my view model. This API call also returns the HTML I need to use in my template (which is basically being read from Section.html).
Obviously this constructor isn't called until I've called applyBindings, so when I get into the success handler for my API call, the template on my component is already set to my default text.
What I need to know is, is it possible for me to update this template? I've tried the following in my success handler as shown above:
ko.components.get("section", function(component) {
component.template[0] = dataFromApi.Html;
});
This does indeed replace my default text with the html returned from my API (as seen in debug tools), but this update isn't reflected in the browser.
So, basically after all that, all I'm really asking is, is there a way to update the content of your components template after binding?
I know an option to solve the above you might think of is to require the template, but I've really simplified the above and in it's full implementation, I'm not able to do this, hence why the HTML is returned by the API.
Any help greatly appreciated! I do have a working solution currently, but I really don't like the way I've had to structure the JS code to get it working so a solution to the above would be the ideal.
Thanks.
You can use a template binding inside your componente.
The normal use of the template bindign is like this:
<div data-bind="template: { name: tmplName, data: tmplData }"></div>
You can make both tmplData and tmplName observables, so you can update the bound data, and change the template. The tmplName is the id of an element whose content will be used as template. If you use this syntax you need an element with the required id, so, in your succes handler you can use something like jQuery to create a new element with the appropriate id, and then update the tmplname, so that the template content gets updated.
*THIS WILL NOT WORK:
Another option is to use the template binding in a different way:
<div data-bind="template: { nodes: tmplNodes, data: tmplData }"></div>
In this case you can supply directly the nodes to the template. I.e. make a tmplNodes observable, which is initialized with your <h3>Loading...</h3> element. And then change it to hold the nodes received from the server.
because nodesdoesn't support observables:
nodes — directly pass an array of DOM nodes to use as a template. This should be a non-observable array and note that the elements will be removed from their current parent if they have one. This option is ignored if you have also passed a nonempty value for name.
So you need to use the first option: create a new element, add it to the document DOM with a known id, and use that id as the template name. DEMO:
// Simulate service that return HTML
var dynTemplNumber = 0;
var getHtml = function() {
var deferred = $.Deferred();
var html =
'<div class="c"> \
<h3>Dynamic template ' + dynTemplNumber++ + '</h3> \
Name: <span data-bind="text: name"/> \
</div>';
setTimeout(deferred.resolve, 2000, html);
return deferred.promise();
};
var Vm = function() {
self = this;
self.tmplIdx = 0;
self.tmplName = ko.observable('tmplA');
self.tmplData = ko.observable({ name: 'Helmut', surname: 'Kaufmann'});
self.tmplNames = ko.observableArray(['tmplA','tmplB']);
self.loading = ko.observable(false);
self.createNewTemplate = function() {
// simulate AJAX call to service
self.loading(true);
getHtml().then(function(html) {
var tmplName = 'tmpl' + tmplIdx++;
var $new = $('<div>');
$new.attr('id',tmplName);
$new.html(html);
$('#tmplContainer').append($new);
self.tmplNames.push(tmplName);
self.loading(false);
self.tmplName(tmplName);
});
};
return self;
};
ko.applyBindings(Vm(), byName);
div.container { border: solid 1px black; margin: 20px 0;}
div {padding: 5px; }
.a { background-color: #FEE;}
.b { background-color: #EFE;}
.c { background-color: #EEF;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="byName" class="container">
Select template by name:
<select data-bind="{options: tmplNames, value: tmplName}"></select>
<input type="button" value="Add template"
data-bind="click: createNewTemplate"/>
<span data-bind="visible: loading">Loading new template...</span>
<div data-bind="template: {name: tmplName, data: tmplData}"></div>
</div>
<div id="tmplContainer" style="display:none">
<div id="tmplA">
<div class="a">
<h3>Template A</h3>
<span data-bind="text: name"></span> <span data-bind="text: surname"></span>
</div>
</div>
<div id="tmplB">
<div class="b">
<h3>Template B</h3>
Name: <span data-bind="text: name"/>
</div>
</div>
</div>
component.template[0] = $(data)[0]
I know this is old, but I found it trying to do the same, and the approcah helped me come up with this in my case, the template seems to be an element, not just raw html
Hi i'm trying to replace some divs with other divs, this works fine but when i try to replace the second load of divs they don't change anymore.
Basicaly I'm trying to create a "winetour" that lets a user choose some options and generates the perfect wine to go along with it.
You get presented with a couple of options (img links) and if you click one the div's content changes and presents another set of clickable images taking you deeper in your process of choosing a great wine.
HTML:
<div id"Gelegenheid">
<img src="Images/Ontbijt.jpg" id="ontbijt" alt="Ontbijt">
<img src="Images/Borrel.jpg" id="borrel" alt="Borrel">
<img src="Images/Dinner.jpg" id="feest" alt="Diner">
<img src="Images/Feest.jpg" id="diner" alt="Feest">
</div>
<div id"Ontbijt" style="display: none"> Some content that shows trough the "tour"</div>
<div id"Borrel" style="display: none"> Some content that shows trough the "tour"</div>
<div id"Dinner" style="display: none">
<img src="Images/White.jpeg" id="ontbijt-licht" alt="ontbijt-licht">
</div>
<div id"Dinner-detail-voor" style="display: none"> Some content that shows trough the "tour"</div>
<div id"Dinner-detail-head" style="display: none"> Some content that shows trough the "tour"</div>
JavaScript:
function continueTour(i) {
if (i==1) {
document.getElementById("Gelegenheid").innerHTML = document.getElementById("Ontbijt").innerHTML;
} else if (i==2) {
document.getElementById("Gelegenheid").innerHTML = document.getElementById("Borrel").innerHTML;
} else if (i==3) {
document.getElementById("Gelegenheid").innerHTML = document.getElementById("Diner").innerHTML;
} else if (i==4) {
document.getElementById("Gelegenheid").innerHTML = document.getElementById("Feest").innerHTML;
} else {
document.getElementById("Dinner").innerHTML = document.getElementById("Dinner-detail-voor").innerHTML;
}
}
So basically if you click on a link that's inside the "Gelegenheid" div you will be taken to for example Dinner, but the problem is, inside dinner there are some more links and i want to link them for example to "Dinner-detail-voor"
I want to make this working with core JavaScript (so no JQuery) but i don't know what's going on?
Thanks in advance!
Found the answer.
Added
document.getElementById("from").style.display = "none" ;
document.getElementById("to").style.display = "table" ;
to each of the javscript index functions, now it works where 'from' is the father and 'to' is the child that is being linked to, not very neat but it works,
If someone has a shorter or alternative solution feel free to post!
first we create an array for all the content, array is base 0 so we start from function myFunction(0); next we create a tag with updated variable in them. the if statement is use to reset the variable when hit max. hope this help.
http://jsfiddle.net/xgay3f83/3/
function continueTour(i) {
var content = ['content 1', 'content 2', 'content 3', 'content 4'];
var target = document.getElementById('target');
var next = i + 1;
var end = content.length;
if(next>end) {
i = 0;
next = 1;
}
var openTag = '<a href="#" class="hvr-grow" onClick = "continueTour('+next+')">';
var closeTag = '</a>';
target.innerHTML = openTag+content[i]+closeTag;
}
I have a WinJS Repeater which is using a template. That template contains a WinJS list view. I can't seem to figure out how to use data-win-bind to set the inner list views itemDataSource.
My Repeater:
<section id="genreView" aria-label="Main content" role="main">
<div id="genreWrapper">
<div id="genreRows" data-win-control="WinJS.UI.Repeater"
data-win-options="{template: select('#genreRowTemplate')}">
</div>
</div>
</section>
My Template which contains a List View:
<div id="genreRowTemplate" data-win-control="WinJS.Binding.Template">
<div id="genreRow">
<h2 class="genreTitle" data-win-bind="innerText: genreTitle"></h2>
<div class="genreMovieListView"
data-win-control="WinJS.UI.ListView"
data-win-bind="itemDataSource : data"
data-win-options="{ layout: { type: WinJS.UI.GridLayout },
itemsDraggable: false,
selectionMode: 'single',
tapBehavior: 'none',
swipeBehavior: 'none',
itemsReorderable: false,
itemTemplate: select('#genreMovieTemplate')}">
</div>
</div>
</div>
My List View's template:
<div id="genreMovieTemplate" data-win-control="WinJS.Binding.Template">
<div class="genreMovieItem">
<img style="width: 175px; height: 250px;" data-win-bind="alt: title; src: posterUrl" />
</div>
</div>
The data for the repeater is similar to this (only it's a binding list):
var repeaterData = [{genreTitle: "titleA", data: new WinJS.Binding.List() },
{genreTitle: "titleB", data: new WinJS.Binding.List() }
{genreTitle: "titleC", data: new WinJS.Binding.List() }
{genreTitle: "titleD", data: new WinJS.Binding.List() }];
The data is created on the fly and each binding list is actually a lot more data so I can't get a good sample of real data.
What I DO get is a repeated control, repeated exactly the number of times as the records in my bound list. What I DON'T get is the binding list displayed. My inner binding list is not getting databound via the data-win-bind. I've tried a few things and I either get nothing or an error. Any help is appreciated. Thanks.
EDIT: I think the right way to bind would be data-win-bind="data-win-options.itemDataSource: data", but doing that throws the following confusing error: "JavaScript runtime error: WinJS.UI.Repeater.AsynchronousRender: Top level items must render synchronously".
I was able to solve my problem, but I don't think I went about it in the right way. I went ahead and set the data source for the repeater, which gives me my genreRows from above. This was always working, it was just the child dataSource I couldn't figure out how to get to. My solution... set it in code after it loads. Nothing fancy, just a solution that feels a bit hacky to me. Here's my code in case it helps someone else get past this problem.
var titleList = $(".genreRow > .genreTitle");
var genreLists = $(".genreRow > .genreMovieListView");
for (var i = 0; i < genreLists.length; i++) {
var title = titleList[i].innerText;
var listControl = genreLists[i].winControl;
tempData.forEach(function (element, i) {
if (element.genreTitle == title)
listControl.itemDataSource = element.data.dataSource;
});
};
Basically the above code assumes the title is unique (which it is). So it uses this as a key to traverse the data and set the itemDataSource that way.
I won't mark this as the accepted answer just in case someone can point out how to do this "right".
Old question, but still deserves a good answer:
I've modified your HTML to show the correct binding syntax.
<div id="genreRowTemplate" data-win-control="WinJS.Binding.Template">
<div id="genreRow">
<h2 class="genreTitle" data-win-bind="innerText: genreTitle"></h2>
<div class="genreMovieListView"
data-win-control="WinJS.UI.ListView"
data-win-bind="winControl.itemDataSource : data.dataSource"
data-win-options="{ layout: { type: WinJS.UI.GridLayout },
itemsDraggable: false,
selectionMode: 'single',
tapBehavior: 'none',
swipeBehavior: 'none',
itemsReorderable: false,
itemTemplate: select('#genreMovieTemplate')}">
</div>
</div>
Notice the winControl.itemDataSource and data.dataSource. Any WinJS control property that is not a standard HTML element property needs the winControl property in front of whatever property you are databinding. So the onclick property of a button element doesn't need it, but WinJS.UI.Command has icon which is not on the underlying button so needs the winControl prefix.
Also, ListView controls bind to a WinJS.Binding.List's dataSource property, not the List itself. For some reason, a repeater binds to the ListView itself however.
I am developing a Windows 8.1 app, and I have some data I want to bind to a listview. For some reason, I am not able to have the data shown, and I am not quite sure where I am making the mistake.
HTML:
<div id="resultTemplate" data-win-control="WinJS.Binding.Template">
<div class="win-type-small result" data-win-bind="innerText:name"></div>
</div>
<div data-win-control="WinJS.UI.ListView" id="resultsView"></div>
Javascript:
var results = [{ name: "quebec" }, { name: "quebec1" }];
var dataList = new WinJS.Binding.List(results);
var resultsListView = document.getElementById("resultsView").winControl;
var resultTemplate = document.getElementById("resultTemplate");
resultsListView.itemTemplate = resultTemplate;
resultsListView.itemDataSource = dataList.dataSource;
I am calling WinJS.UI.processAll() at the top of my javascript.
I don't see anything wrong with it, but you could try setting the itemTemplate in the html.
<div id="resultTemplate" data-win-control="WinJS.Binding.Template">
<div class="win-type-small result" data-win-bind="innerText:name"></div>
</div>
<div data-win-control="WinJS.UI.ListView" id="resultsView" data-win-options="{ itemTemplate: select('#resultTemplate')}"></div>
Notice the new data-win-options attribute in ListView tag