I have two Marko components that I'd like to include in other components whenever they render on an Express server: <main-header/> and <main-footer />.
components/main-header/index.marko is as follows:
<lasso-page />
<!DOCTYPE html>
<html>
<head>
<lasso-head />
</head>
<body>
<nav>...</nav>
And components/main-footer/index.marko is:
<footer>...</footer>
<lasso-body />
</body>
</html>
The page I want to render on a certain route would look like:
<main-header />
//component content
<main-footer />
However, I get an error of Missing ending "body" tag for main-header, so obviously this kind of EJS-partials like syntax isn't allowed. Is there a better way to do this without having a single index.marko file that is rendered in every route handler?
Here's the docs on using layouts:
https://markojs.com/docs/core-tags/#layouts-with-nested-attributes
The docs mention using #tags which allow passing named content chunks (if you wanted to put some stuff into <head> and other stuff into <body>), but if you only have a single content chunk to pass, you can use the default content.
You can create a layout that uses the <include> tag to render content passed to it:
<html>
<body>
<include(input.renderBody)/>
</body>
</html>
Then use the layout, passing body content:
<custom-layout>
Content goes here
</custom-layout>
Related
I am trying to use peerjs in vue app. So I added the cdn script in vue index.html file's header like this.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta data-n-head="true" name="viewport" content="width=device-width, initial-scale=1.0">
<title>peer</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/peerjs/0.3.9/peer.min.js"></script>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
Now in a components' mounted hook, I am doing this to just console the id
var peer1 = new Peer();
peer1.on('open', function(id) {
console.log('My peer1 ID is: ' + id);
});
Nothing happens.
I then created a simple html file and run that html file I was able to see the id.
Next I tired to see XHR tab, I see when running a plain html file, two ajax calls is sent and in the result an ID is returned. But in vue, there is nothing like this. All I get a socket that returns this values
{websocket: true, origins: ["*:*"], cookie_needed: false, entropy: 1058218289}
cookie_needed
:
false
entropy
:
1058218289
origins
:
[":"]
websocket
:
true
One more thing, peers js documentations says to use api key, but if I use api key nothing happens in vue or html. Without the key, in html file I get the id.
Anyone knows please help me. Thank you.
Is there a way to add a script tag declared in view B to the list of scripts in view A (which calls B)?
The example below should make it clear what I need.
I have a base template A:
<html>
<head>
<title>#title</title>
<!-- declared stylesheets -->
</head>
<body>
#content
<!-- Java script dependencies -->
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
</body>
</html>
Note that the base view declares dependencies to jquery.js and bootstrap.js at the end of the file. This is OK except for the following case:
#base(title) {
#header()
#navigation()
<div class="container">
#content
</div>}
The navigation view has a script tag that depends on jquery already being loaded.
When I load the page I get an error stating that "$ symbol is not defined" which makes sense because the script is parsed before jquery is loaded.
Is there a way for me to add the script declared in navigation at the end of the base view (after the declaration of jquery)?
I've tried moving the dependency to jquery to the <head></head> section and everything works as expected, but I would like to keep the current layout.
Edit: To be more clear, I want to send the script dependencies from #navigation view to #base view .
Take a look to Play's doc for moreScripts and moreStyles equivalents (last section in doc)
De dacto it deosn't need to be named scripts so you can use your own name, also you can use it for sending other blocks of HTML into higher level view (layout).
See answers to similar quesion
So it can be i.e.:
#navigationScripts = {
<script src="/assets/my-navigation.js"></script>
}
#base(title, navigationScripts) {
#header()
#navigation()
<div class="container">
#content
</div>
}
And in layout:
#(title: String, navigationScripts: Html = null)
<html>
<head>
<title>#title</title>
<!-- declared stylesheets -->
</head>
<body>
#content
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
#navigationScripts
</body>
</html>
I am using Handlebars in an Express Node.js app. My layout.html file includes a <head> section. How can I make the <head> section different for different pages? (So that I can, for example, reference a JavaScript file in only one page, and vary the <title> for each page.)
layout.html looks like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src='/public/ajsfile.js'></script>
<link type='text/css' href="/public/style.css" rel="stylesheet">
</head>
<body>
{{{body}}}
</body>
</html>
(I am imagining varying the <head> content with something analogous to {{{body}}} in the above, but with {{{head}}}.)
This is a great question and, in my mind, a glaring weakness in Express's view model. Fortunately, there is a solution: use Handlebars block helpers. Here's the helper I use for this purpose:
helpers: {
section: function(name, options){
if(!this._sections) this._sections = {};
this._sections[name] = options.fn(this);
return null;
}
}
Then, in your layout, you can do the following:
<head>
{{{_sections.head}}}
</head>
<body>
{{{body}}}
</body>
And in your view:
{{#section 'head'}}
<!-- stuff that goes in head...example: -->
<meta name="robots" content="noindex">
{{/section}}
<h1>Body Blah Blah</h1>
<p>This goes in page body.</p>
You can make the follow:
layout.hbs
<head>
<title>{{title}}</title>
{{#each css}}
<link rel="stylesheet" href="/css/{{this}}" />
{{/each}}
</head>
app.js
router.get('/', function (req, res, next) {
res.render('index', { title: 'MyApp', css: ['style.css', 'custom.css'] });
});
Result:
<head>
<title>MyApp</title>
<link rel="stylesheet" href="/css/style.css" />
<link rel="stylesheet" href="/css/custom.css" />
</head>
Maybe, you could use this implementation of the section helper: https://github.com/cyberxander90/express-handlebars-sections
You just need to install it and enable it:
yarn add express-handlebars-sections # or npm
const expressHandlebarsSections = require('express-handlebars-sections');
app.engine('handlebars', expressHandlebars({
section: expressHandlebarsSections()
}));
Hope it helps.
Younes
I know this is an older question but I wanted to point out a clear alternative solution to what you are asking (I'm not entirely sure why nobody else spoke about it over the years). You actually had the answer you were looking for when you bring up placing things in {{{head}}} like you do for {{{body}}}, but I guess you needed help understanding how to make it work.
It seems possible that most of the answers on this page are geared towards Node "Sections" because you speak about the different sections of HTML you've included in your layout file that you want to change. The "Sections" everyone is speaking about in this thread seems to be a technique, although I may be mistaken, originating from Microsoft's Razor Template Engine. More info: https://mobile.codeguru.com/columns/dotnet/using-sections-and-partials-to-manage-razor-views.htm
Anyway Sections work for your question, and so could "Partials" theoretically (although it may not actually be the best option for this). More info on Partials:
https://www.npmjs.com/package/express-partial
However, you simply asked for a way to alter the HTML tag content of your template layout in Handlebars, and assuming we are talking about HTML head tags, all you need to do is replace the content you have in your template layout HTML head tags with one of these (I use 3 brackets because it seems HTML would be included and you don't want it escaped):
<head>
{{{headContent}}}
</head>
Then you just dynamically pass whatever data you want through the route you create in your app.js file to "get" the page like so (I am mostly taking the code #Fabricio already provided so I didn't have to rewrite this):
router.get('/', function (req, res) {
res.render( 'index', { headContent:'I DID IT!' });
});
Now when you load your page, "I DID IT!" will be where you expect it to show up.
I want to use CActiveForm's AjaxValidation.
My layout view file was like this before enabling AjaxValidation:
<html lang="tr-TR" dir="ltr">
<head>
<script src="<?php echo Yii::app()->request->baseUrl; ?>/js/jquery.js"></script>
</head>
As you see i'm calling jquery framework on my layout page (because i'm using on every page).
And i decided to use CActiveForm's ajax validation. Firstly enable enableAjaxValidation while calling it:
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'otel-form',
'enableAjaxValidation'=>true,
)); ?>
And then uncomment this on my controller
$this->performAjaxValidation($model);
But i got $(...).yiiactiveform is not a function error. When i check source code of page :
As you see, one more jquery library included, too. So there are 2 jquery files on page. Because of this i'm getting error. Next i put something like this for disabling jquery.
Yii::app()->clientscript->scriptMap['jquery.js'] = false;
Now jquery is loading only once. But this result is :
<html lang="tr-TR" dir="ltr">
<head>
<script type="text/javascript" src="/istanbulcityhotels/assets/cb2686c8/jquery.yiiactiveform.js"></script>
<script src="/istanbulcityhotels/js/jquery.js"></script>
</head>
jquery.yiiactiveform.js calling BEFORE jquery.js . It should called AFTER jquery.js.
It confused a bit. What should i do?
ADDITIONAL
Yes, i read this question because titles' are really similar, but question isnot same.
Thank you.
You should not be including jQuery manually from your layout. Instead of doing this, include it from within your Controller base class:
public function init() {
Yii::app()->clientScript->registerCoreScript('jquery');
}
Don't forget to call parent::init() from within your concrete controllers.
It seems CActiveForm inserts the scripts before the title tag using CClientScript::POS_HEAD constant. So a workaround is to add this code
<?php
$cs=Yii::app()->clientScript;
$cs->scriptMap=array(
'jquery.js'=>false
);?>
to the top of the main layout file in order stop it from loading jquery, then put the title tag after you load your jquery file
<script src="<?php echo Yii::app()->request->baseUrl; ?>/js/jquery.js"></script>
This way jquery.yiiactiveform.js will be loaded right after jquery.
just put your own jquery on tag title,
just like this:
<script src="/istanbulcityhotels/js/jquery.js"></script>
<title>your title</title>
I'm defining page with some vars and methods. Then I wanna use it in html markup (for example data-win-bind="textContent: myPage.variable). How can I access page variables in html markup?
In the JavaScript code behind your page, say default.js, you'd include your ViewModel for the data binding, something like:
(function(){
WinJS.Namespace.define("MyModel.myPage", {
variable : null
};
MyModel.myPage.variable = 'foo';
})();
Then in when the page is activated (in default.js), you'll need to initialize the bindings with a call like
WinJS.Binding.processAll(document.body, MyModel);
There's quite a bit more functionality available though, so this is just a simplistic one-way binding case that should get you started. For more info, check out the Quickstart: binding data and styles.
You have to use javascript here's the skeleton:
<html>
<head>
<script type="text/javascript">
//Code goes here
</script>
</head>
<body>
</body>
<html>