Problems with vue.js content rendering - javascript

I've just learning Vue.js and I'm getting stuck with some problems with its rendering.
Let's say I have the following lines of code:
index.html
<div id="header">
<h5>{{pageName}}</h5>
<p>{{pageSubtitle}}</p>
</div>
app.js
var header = new Vue({
el: '#header',
data: {
pageName: 'CuteCat',
pageSubtitle: 'World of cats'
}
});
When I load the page, the CuteCat and World of cats is shown perfectly but when I view source, this is what I get:
<div id="header">
<h5>{{pageName}}</h5>
<p>{{pageSubtitle}}</p>
</div>
What can I do to replace the mustaches brackets in the view source with its declared value like this?
<div id="header">
<h5>CuteCat</h5>
<p>World of cats</p>
</div>

Just as #yuriy636 is telling you, this is not an error by any means.
Vue is a JavaScript UI framework, making its magic in the client (i.e. in the browser). In the source view you see what's been loaded from the server and what you see is exactly that.
If you disable JavaScript for a session and reload your app, the double mustaches will be visible. Because they are replaced by Vue when JS is on.
Edit: In the DOM, however everything is normal after Vue rendering, just as you would expect it.

Related

Open uikit modal on page load

I'm currently working on a project in Flask and I'd like for (under specific circumstances) open up a modal when the page loads. Currently what I have is as follows:
My view function passes a variable 'open_modal' into the template
return render_template('index.html', open_modal = "window.onload() = function(){UIkit.modal(#modal1).show();};")
and inside the template itself, there's a part in the template which looks like:
<script type="text/javascript">
{{ open_modal }}
</script>
And the modal itself looks something like:
<div id="modal1" uk-modal>
<div class="uk-modal-dialog uk-modal-body">
Test test!
</div>
</div>
And so what I was hoping is that whenever I use the render_template with the kwarg 'open_modal' as that value above, it'd insert the javascript fragment into the template and then ta-dah! The modal would open when the page loads. However, this doesn't seem to work, and I can't figure out why.
Admittedly, I have no experience with javascript so I would have no clue if the script fragment that is inserted by 'open_modal' even works, but I'd rather stick to vanilla javascript because this is the only bit of javascript in my program, and I'd rather not add more bulk to it unnecessarily with jquery etc.
Thanks a bunch if you can help!
The onload is not a function, it's a property of window. You have to assign a function to it:
return render_template('index.html', open_modal = "window.onload = function(){UIkit.modal('#modal1').show();};")

How to create an Electron app with multiple sections

I'm trying to create an Electron app that has multiple "pages".
In my case, I'm trying to make an app with a sidebar that has different sections. Once a section is clicked, the main window's content changes to render the appropriate content for the section.
I'm new to JS so sorry if this is a dumb question, but as of now, whenever I try to go to a section of the app, I get a white-flash screen for a second before everything loads again.
Example: https://i.imgur.com/qOyuYsz.gif
I know this has to do with Electron reloading the Chrome engine, but how can I make it so when a section is clicked, the content is displayed automatically without any "flashes" or weird things?
Basically: how can I build a GUI with lots of components using Electron?
My code for my index.html is:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Rupture Tools</title>
<link rel="stylesheet" href="./photon/css/photon.min.css">
</head>
<body>
<div class="window">
<div class="window-content">
<div class="pane-group">
<div class="pane-sm sidebar">
<nav class="nav-group">
<h5 class="nav-group-title">1 Click Generator</h5>
<a class="nav-group-item active">
<span class="icon icon-home"></span>
Dashboard
</a>
<a href="accounts.html">
<span class="nav-group-item">
<span class="icon icon-user-add"></span>
Accounts
</span>
</a>
<span class="nav-group-item">
<span class="icon icon-cloud-thunder"></span>
Activity
</span>
<span class="nav-group-item">
<span class="icon icon-check"></span>
Check Scores
</span>
<span class="nav-group-item">
<span class="icon icon-cog"></span>
Settings
</span>
<span class="nav-group-item">
<span class="icon icon-help-circled"></span>
Help/FAQ
</span>
</nav>
</div>
<div class="pane">Home</div>
</div>
</div>
</div>
</body>
</html>
Please help! I'm clueless at this, been searching everywhere. I come from Python where there isn't much of any front-end development or GUI designing. Thanks!
There is "sort of" a solution here, but it uses something called Sass and as far as I know using something like React or Angular is better. I've never used either of those.
Electron apps are very similar to web apps. The traditional way of navigating between HTML documents doesn't work well for apps as you noticed. That's why web apps are developed as single-page applications (SPA) nowadays. It simply means loading and replacing parts of the page manually using JavaScript when the user navigates. There are several ways to implement this, but here's an example how it could be done for your code:
// Get all the navigation links to an array
const naviLinks = Array.from(document.getElementsByClassName("nav-group-item"));
const contentEl = document.getElementsByClassName("pane")[0];
naviLinks.forEach((linkEl) => {
// Listen click event for the navigation link
linkEl.addEventListener("click", e => {
// Prevent default behavior for the click-event
e.preventDefault();
// Get the path to page content file
const href = linkEl.getAttribute("href");
if (href) {
// Use node.js fs-module to read the file
const fs = require("fs");
fs.readFile(href, (err, data) => {
if (err) {
throw err;
}
// show the selected page
contentEl.innerHTML = "";
contentEl.insertAdjacentHTML("beforeend", data);
})
}
})
})
Note that the page content HTML files (accounts.html etc.) should only have the content for the "pane" div. You also need to pass nodeIntegration:true when creating your BrowserWindow-object in the main-process, so you can use require to load the fs-module:
new BrowserWindow({
webPreferences: {
nodeIntegration: true
}
}
If the page content files are large, navigation may seem slow, because files are read and pages are rendered on every click. One optimization to help with that is to read files and create page elements off-screen already at page load and then just swap the elements on click-events. Alternatively you could put the page contents in <template>-elements and swap them. I'll leave these for you to try out by yourself, if you're interested.
There are loads of JavaScript frameworks that can help you with creating SPAs. Some popular ones at the moment are React, Angular and Vue. "How can I build a GUI with lots of components?" is one of the questions front-end JavaScript frameworks can answer, but there's of course a learning curve. When you feel the need to start splitting your GUI into reusable or hierarchical components, it's probably a good idea to look into those JavaScript frameworks.
I made some code a while back to do this (Unfortunately it's rather complicated but it shouldn't be so hard to implement it).
You put this function on every page:
function loadPageWithIframe (url) {
var hiddenPage = document.createElement("iframe");
hiddenPage.setAttribute("src", url);
hiddenPage.style.display = 'none';
document.body.appendChild(hiddenPage);
hiddenPage.onload = function () {
var frameDocument = hiddenPage.document;
if (hiddenPage.contentDocument) {
frameDocument = hiddenPage.contentDocument;
} else if (hiddenPage.contentWindow) {
frameDocument = hiddenPage.contentWindow.document;
}
document.open();
document.write(frameDocument.documentElement.innerHTML);
document.close();
window.history.pushState("", document.title, url.replace('https://' + window.location.hostname, ''));
}
}
And this code in your Electron file:
mainWindow.webContents.on('will-navigate', function (evt, url) {
evt.preventDefault();
mainWindow.webContents.executeJavaScript('loadPageWithIframe("' + url + '");');
});
And if you put the code in correctly it should work automatically, without any extra code.
The way this works is you call the loadPageWithIframe function when you want to go to a url, then it makes an iframe and loads the page, copies the all the html from the iframe and overwrites the current page's HTML with the iframes HTML.
But instead of calling the loadPageWithIframe function on manually on every click you can use Electron's will-navigate event to let us know that it's going to another page, then call the loadPageWithIframe (this is the purpose of the electron code that I posted).
I hope that Helps :)

How can I get a template to replace, rather than append to, the existing one?

I'm trying to navigate from my home page to another page (template) in my Meteor app.
I installed the iron:router package and added the following code:
First, this template (placeholder content) in my html file:
<template name="scheduleOpenExisting">
<h2>Open Existing Schedule</h2>
</template>
Then this in my .js file:
Router.route('/scheduleOpenExisting');
...and finally this to a menu item:
<li>Open Existing</li>
...which I changed from:
<li> Open Existing
When I select that menu item, it does change the URL from http://localhost:3000/ to http://localhost:3000/scheduleOpenExisting, but it appends the scheduleOpenExisting template to the bottom of the page, rather than navigating to a new page, or in an Ajaxy way replacing the existing content.
So how can I get the scheduleOpenExisting template to replace, rather than append to, the "home page"?
UPDATE
I haven't had time to test it yet (this is a home project, and I had to go to work), but I moved all my code out of the single .html and .js files into various places:
Scheduler
Client (folder)
main.html (moved the two templates from scheduler.html for the "first page" here)
main.js (moved the .isClient code from scheduler.js here)
Templates (folder)
openExistingSchedule.html (contains a template; will add more later, as the project grows)
Server (folder)
scheduler.js (moved the .isServer code here)
...and will see if it still works, and works any differently, with this new project structure.
UPDATE 2
It still does the same thing, even with the revamped structure - the template is inserted at the bottom of the page.
Nevertheless, it's really great that Meteor still runs just fine after moving the files all over creation. Other environments would be likely to break, and throw misleading err msgs when doing such a thing.
UPDATE 3
In \client\main.html, I've got this:
<head>
<TITLE>Crew Scheduler</TITLE>
</head>
<body TEXT="#000000">
<div class="container">
{{> mnuScheduler}}
{{> tblScheduler}}
</div>
</body>
<template name="mnuScheduler">
<ul class="top-level-menu">
<li> Schedules
<ul class="second-level-menu">
<li>Open Existing</li>
. . .<template name="tblScheduler">. . .
In \client\templates\openExistingSchedule.html I've got this:
<template name="scheduleOpenExisting">
<h2>Open Existing Schedule</h2>
</template>
...and in \client\routing.js I've got this:
Router.route('/scheduleOpenExisting');

How to render template without JavaScript in meteor?

I am using iron:router in meteor. In my case I wanna include Template in an Iframe.
template.html
<iframe src="{{pathFor 'MyTemplate'}}" width="100%"></iframe>
route.js
this.route('MyTemplate', {path: '/MyTemplate',layoutTemplate:'MyTemplate'});
When I render this temple in an iframe. It render with javascript and CSS. I need only css here. Is there anyway to restrict the JavaScript in specific route.
I'm not sure if its quite what you want but you can render HTML without meteor adding the javascript by doing this kind of thing:
Router.route('/MyTemplate', function () {
this.response.end('<html><h1> hello world </h1></html>');
}, {where: 'server'});
});
with that code in the server section.

Knockout + Ajax Content results in multiple binding error

I have built a web application with multiple pages. Some of them are Knockout-driven.
I am trying to apply some Ajax-optimized page loading and stumble over the following issue.
Say I have the following general page structure
<body>
<div id="content">
</div>
</body>
And the following view, which is using Knockout. I include the call to applyBindings inline for being able to load the right ViewModel for every view.
<section id="editor">
<ul data-bind="foreach: items">
....
</form>
</section>
<script>
ko.applyBindings({items: {}}, $("#editor").el)
</script>
I load the view asynchronously into div#content for example using JQuery.load("editor.html #content")
The first page load works fine, but when navigating away (again using JQuery.load) from this view and coming back again I receive the error:
You cannot apply bindings multiple times to the same element.
I have already tried to apply ko.cleanNode but with no success. What am I missing? The #editor node should be removed from the DOM when other content is shown. So I really do not understand how to clean bindings or reinitialize knockout.
Note: I do not want the old data, I want to initialize the Bindings like on a freshly loaded page
Could you test your $("#editor").el in console? It doesn't work in standard jQuery.
If your $("#editor").el returns undefined, your ko.applyBindings({items: {}}, $("#editor").el) is essentially binding to window.document.body.
You may try
ko.applyBindings({items: {}}, $("#editor").get(0));
...
// call cleanNode before loading new page.
ko.cleanNode($("#editor").get(0));
$("#content").load( "newpage.html" );
if your bindings in "editor" section doesn't change,i suggest you to load(AJAX) only json data from server,and replace(modify) your viewModel in the browser,in that way knockout will refresh the dom automaticly.

Categories