I'm working with PHP Fat Free and I am attempting to create a layout/sublayout system which will eventually mimic MVC to some extent. I have a main layout which has placeholders (essentially the backend sets different sublayout or partial file paths and then the view takes care of calling the rendering of that file name. This all works great.
The issue I'm running into is when I need inline javascript in my sublayout to run after scripts in the main layout (after the jquery include line, for instance). In a previous framework I was using, I was able to do us output buffering ob_start and ob_get_clean to grab the script in the sublayout and then pass that to the layout to display below the script line. I hope that makes sense, but if not, here's the current code I'm working with in F3.
The route:
$f3->route('GET /test',
function($f3) {
// set the sublayout name
$f3->set('sublayout', 'testpage.php');
// render the whole shebang
echo View::instance()->render('testlayout.php');
}
);
The layout:
<!DOCTYPE html>
<html>
<head>
<title>Test Layout</title>
</head>
<body>
<h1>Test Layout</h1>
<?php echo View::instance()->render($sublayout) ?>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js" />
<!-- inline script should go here -->
</body>
</html>
The sublayout:
<h2>My Test Page</h2>
<div id='message'></div>
<script>
// This code needs to be placed AFTER the jquery include in the main layout
$(function(){
$('#message').html('This is my message');
});
</script>
I tried extending the view to include a "beginRegion" and endRegion function that basically handled the ob_start and ob_get_clean portion so that my inline script could be picked up, but once I'm in the sublayout I wasn't able to figure out how to pass that buffered code back to the layout so it could be echo'd after the jquery include.
Before you tell me that I should not be using inline script, I know this and most things I do are in external script files which I have a solution for including, but there are times when I need it inline and that's where I'm stuck.
Is there a way to handle what I'm trying to do with output buffering, or better yet is there a better way to solve this than the output buffering approach?
Update:
Best practices generally dictate that you should include the script at the bottom of the page right before the closing body tag. If I put the script above the sublayout, it breaks both our FE best practices and has the disadvantage of blocking the rest of the page while the script downloads. That's why I'd like to keep it structured the way I have noted instead of placing the jquery include ABOVE the sublayout.
I don't understand what's the problem.
Your layout is:
<!DOCTYPE html>
<html>
<head>
<title>Test Layout</title>
</head>
<body>
<h1>Test Layout</h1>
<?php echo View::instance()->render($sublayout) ?>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js" />
<!-- inline script should go here -->
</body>
</html>
You want to include sublayout after jquery usage. So why not to write it like this? :
<!DOCTYPE html>
<html>
<head>
<title>Test Layout</title>
</head>
<body>
<h1>Test Layout</h1>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js" />
<!-- inline script should go here -->
<?php echo View::instance()->render($sublayout) ?>
</body>
</html>
Also You can write custom function. Lets say You've folder with partials or something else more structured and want to use it:
$f3->set('partial',
function($file) {
$file .= (strpos($file, '.php')>0)? '' : '.php';
if(!is_file($file)) return '';
return View::instance()->render($file);
}
);
and then use it like:
<!DOCTYPE html>
<html>
<head>
<title>Test Layout</title>
</head>
<body>
<h1>Test Layout</h1>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js" />
<!-- inline script should go here -->
{{ #partial('partials/testpage') }}
</body>
</html>
I knew why You want to do so. But what's the problem to decouple scripts in scripts.php file and HTML,php part to another file and render them as needed? (:
From a google groups discussion I had, someone offered up a JS solution that might work:
inside your layout:
<head>
<script>
var callbacks=[];
</script>
</head>
<body>
<script src="...jquery.min.js"/>
<script>
$.each(callbacks,function(i,func){func.call(null,jQuery);}) //<< triggers all queued callbacks
</script>
</body>
inside your sublayout:
<h2>My Test Page</h2>
<div id="message"></div>
<script>
callbacks.push(function($){
//do something with jQuery
});
</script>
Here's the link:
https://groups.google.com/forum/#!topic/f3-framework/iGcDuDueN8c
Related
I have an HTML "chunk" of code with HTML and JS in it so I could easily include it with PHP. I also want it to have CSS styling but according to standards you are not "allowed" to do that - while it works it makes the page invalid. CSS is only allowed in <head> and not in the middle of the page (not untill HTML5.2 at least). So I thought about appending similarly named but separate .css file in the head, but with PHP and not JS (for performance sake)
<head>
<!-- PHP needs to include button.css here AFTER $App->INC("button"); has been called -->
</head>
<body>
<?php
$App->INC("button");
//This basically does 'require_once("button")';
//What do I need to add to the INC method to include css file in the head?
//Similar to $("head").append() but with PHP
?>
</body>
css file with the same name should be added to a <head> section.
PS:
This may seem as a design flaw and may as well be but here is the thought behind this.
I have a piece of code that when included in the right place of the
body generates a "loading screen" (or other UI elements that
can't/shouldn't be nested anywhere else but in the <body> of
the website.
It's got styling in a separate file
I send it to other user
They include it with a method of an "App" class which only does two
things: includes the file itself and css file nearby
Then they only use 1 line of code to put it where they want it and
not in 2-3 other places so the code is more manageable
Example:
You may try this:
<?php
ob_start();
$App->INC("button");
$button = ob_get_clean();
?>
<head>
<!-- Do your inclue here -->
</head>
<body>
<?= $button ?>
</body>
You can put the ob_start() / ob_get_clean() stuff inside button.php and return the content via your INC() method. Then you can save the content directly into $button like this: $button = $App->INC("button");.
But your example looks like a design problem. However I hope this will do the trick.
This could be a possible redesign:
<?php
$App->loadModule('button'); // Loads the module, the module registers stylesheets and content.
$App->loadModule('another_module'); // Load more modules ...
<head>
<?php $App->renderModuleStylesheets(); ?>
</head>
<body>
<?php $App->renderModuleContent(); ?>
</body>
If you include the CSS directly in the component itself, or expect the component to dynamically load the relevant CSS, then it could be quite difficult to maintain or customize. I am not saying you shouldn't go this route but be careful about asking your components to do too much.
A hook system as pointed out in the comments is one way to handle this.
Another simple way is to provide default styling which users can override. This is probably the simplest way to allow different styling for each component.
<head>
<!-- Provide some defaults. Users should not customize this one. -->
<link rel="stylesheet" type="text/css" href="default.css">
<!-- User's can customize this file to override the default styling.-->
<link rel="stylesheet" type="text/css" href="custom.css">
</head>
<body>
<?php $App->INC("button"); ?>
</body>
button.php - is only responsible for rendering a button. The separate CSS files will actually style it.
<?php
echo <input type"submit" class="button" value="Submit">
default.css - applies default styling
.button {
color: blue;
}
custom.css - overrides the default styling
.button {
color: red;
}
Final note, you may also want to look into using a main template file which sub-views inherit. This helps to reduce the number of full HTML files which link to your CSS files. The idea is to have 1 (or a few) template files that views inject themselves into. Here's some pseudo code.
frontend.php
<html>
<head>
<!-- Links to CSS files here. -->
</head>
<body>
<?php $placeholder('body'); ?>
</body>
Login.php
<?php inherits('frontend.php')->body; ?>
<form id="login">
...
Register.php
<?php inherits('frontend.php')->body; ?>
<form id="register">
...
About-Us.php
<?php inherits('frontend.php')->body; ?>
<p>About Us</p>
...
Let's say I'm starting with a PHP application. On one of the pages on the site, there's a complex interactive app that I want to use Angular for. The problem is, I still want the header and footer of that page to match the rest of the site. I would love to be able to do something like this:
// main-template.php
<html>
<head>
<title>My Site-wide Header</title>
<script src="site-wide-script.js"></script>
<link href="site-wide-styles.css" rel="stylesheet">
<?php if ($somevar == true) : ?>
<?php echo "Yes, it has to be PHP"; ?>
<?php endif; ?>
</head>
<body>
<header>
<ul>
<li>Home</li>
<li>About</li>
<li>Contact</li>
</ul>
</header>
<!-- Drop entire Angular application here -->
</body>
</html>
It somewhat works for me to just PHP include the Angular HTML file there, but that's pretty janky because, of course, the Angular index.html file already includes a html, body, etc. tags. Of course I could DOM parse the Angular file and fix all that before including...but I'd prefer a better solution.
In my searching I can't seem to find any officially recommended way of doing this. Actually I can't seem to find any examples of anyone doing this at all–all my searches just turn up people doing something similar with AngularJS, not Angular. Is there any decent way to accomplish this with Angular?
You should be able to do what you want to do.
Here's the content of a index.html for a web based chat program I did as a HW project (the back end was much more fun...).
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>crap chat</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="bootstrap.min.css" rel="stylesheet" />
</head>
<body class="m-a-1">
<?php print("Hello World ".date("r",time())."<br />\n"); ?>
<app></app>
<script type="text/javascript" src="inline.bundle.js"></script>
<script type="text/javascript" src="polyfills.bundle.js"></script>
<script type="text/javascript" src="styles.bundle.js"></script>
<script type="text/javascript" src="vendor.bundle.js"></script>
<script type="text/javascript" src="main.bundle.js"></script>
</body>
</html>
As long as you keep the same js file references and style sheets, styles (on <body> tag) etc. then you should be able to drop that in and toss in the <app></app> tag set just where you want it.
Just for giggles I renamed the file to index.php on my server, added a print statement to print date/time page was loaded, no issues.
As of angular6, this should be possible using angular elements.
Your code would then simply be
// main-template.php
<html>
<head>
<title>My Site-wide Header</title>
<script src="site-wide-script.js"></script>
<link href="site-wide-styles" rel="stylesheet">
<?php if ($somevar == true) : ?>
echo "Yes, it has to be PHP";
<?php endif; ?>
</head>
<body>
<header>
<ul>
<li>Home</li>
<li>About</li>
<li>Contact</li>
</ul>
</header>
<your-component-name></your-component-name>
</body>
You can find a guide on how to create angular elements at https://angular.io/guide/elements - in principle, it is no harder than just creating a component
As someone might still come across this issue (like me), I want to share my solution:
As we are currently changing from a pure PHP page to an Angular approach, we need to include some basic php-stuff in the head of the index file of the Angular build process. Therefore, I added a postbuild-Step, which will automatically run after the build-step.
However, this step is running a node.js script which simply adds the php include we need in the index.php of the dist-Folder
const fs = require('fs');
const path = require('path');
const sourceDir = path.join('dist', 'path');
const phpTag = "<?php include_once './some.php' ?>\n";
const file = path.join(sourceDir, 'index.php');
fs.readFile(file, 'utf8', function (err, content) {
if (err) throw err;
if (!content.startsWith(phpTag)) {
content = phpTag + content;
fs.writeFile(file, content, 'utf8', function (err) {
if (err) throw err;
});
}
});
and these are the entries of my package.json:
"scripts": {
"build": "ng build",
"postbuild": "node ./addPHPTag.ts",
I'm trying to make a simple php script that puts a list in the header, here is what I have
<html>
<head>
<?php
function menu1($link1, $button1) {
echo "<ul><li><a href = '$link1'>$button1</a></li></ul>";}
menu1('index.php','Home')
?>
</head>
<body>
<p>Home</p>
</body>
</html>
Yet for some reason when I run the script it outputs this
<html>
<head>
</head>
<body>
<ul><li>Home</li></ul>
<p>Home</p>
</body>
</html>
Is there any way I can get this to post in the head?
Thanks in advance!
The <head> element can only contain certain special elements, such as <title>, <link>, and <meta>, among others. It cannot contain any elements which are rendered on the page.
If you view source, you'll see that the markup is being output the way you requested. However, this markup is invalid, and is being "repaired" by the browser by moving these elements into the <body>.
They are good practices put jQuery the bottom of the page, before the </ body>, but when you have an include PHP in the middle of the page and in this include I have that jQuery code like this:
[code of index.php]
[include]
<script>
$(function() {
<?php
echo "$('#".$_SESSION['user']['flags']."').attr('selected', true);";
?>
});
</script>
[/include]
[code of index.php including jQuery.js here before </body>]
Firebug tells me that $ is not defined. I used "defer" but it does not work either. I searched Stackoverflow but do not know how to fix it.
Here my code:
index.php
<!doctype html>
<html class="no-js" lang="es">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="robots" content="noodp, noydir">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body id="body">
<?php
include './step1.php';
?>
<!-- jQuery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>
<script type="text/javascript" src="js/main.js"></script>
</body>
</html>
step1.php
<script>
$(function() {
<?php
echo "$('#".$_SESSION['user']['flags']."').attr('selected', true);";
?>
});
</script>
If you replace the "$(function(){" section with window.onload you can ensure that all script files have been loaded before attempting to fire your function.
However, be aware that this fires much later that jQuery's document.ready. jQuery's method fires when the dom is loaded whereas window.onload waits until the whole document and it's scripts have been loaded.
More info and example here:
https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onload
You included the jQuery.js after the inclusion of that script. Move your jQuery.js include above include statement that contains your js code.
Answer to the problem:
You have included the step1.php before including jQuery.js. This is why it won't work. Include jQuery.js before including step1.php.
Answer regarding jQuery in end of HTML body:
Yes, it's a good practice but that seems to me as a micro-optimization. As it would speed up the loadtime. But you can only do that if you include your written jQuery code after including the actual jQuery.js library. Since you're not able to do that in the current contruction, you need to change the order to make it work.
Otherwise general debugging techniques apply:
Check your browser. Right click. Inspect element. Open tab network. Make sure the jQuery.js file is really included so you'll have a HTTP status 200 code on this request.
Make sure jQuery is really inside jQuery.js and the file is not empty or having other contents.
Make sure jQuery not included twice.
Also checkout:
https://api.jquery.com/jquery.noconflict/
http://www.sitepoint.com/types-document-ready/
or try:
jQuery(document).ready(function(){ /* [code here] */ });
The question is fairly simple, yet I've been looking around for an hour and found nothing:
make a page that is exactly the same as the home page, but a specific div has altered content
example index.html:
<html>
<head>
<title>title</title>
<style type="text/css">
/* css goes here */
</style>
</head>
<body>
<div id="stay">I wont change</div>
<div id="change">I will change</div>
</body>
</html>
so I want to be able to code a page so that it inherits the entire html from the index page (WITHOUT COPYING THE CODE), but a specific div (here with the id #change) to have different content. How would I go about doing this?
You don't really "inherit" code snippets, but I understand that you're trying to reuse the page content. From your posted code, it's hard to tell exactly how the change differs from the index. Is it just a content change or does the index page not have that div?
You have a couple of options. If just the content of the div is changing, you could use the same php page and then use jquery to change the content of the div, so something like
index.php
<? php include("page.php"); ?>
other page
<? php include("page.php"); ?>
// javascript to modify div
You could break the page into chunks and just include them as needed, so you could have a top.php and a bottom.php, and the index page could do
<? php include("top.php"); ?>
<? php include("bottom.php"); ?>
And then your similar page could do something like
<? php include("top.php"); ?>
// custom stuff here
<? php include("bottom.php"); ?>
If neither of these solutions work you could always use a templating engine to create a page template, though that may be a little much for your situation.
I see you have tagged this question in php So, I will give you answer inclusive of php implementation.
Create 3 pages. index.php about.php and foo.php
The objective is to show some content in index.php but all content in about.php
Call this page foo.php
<html>
<head></head>
<body>
<p> Show this in index.php </p>
<?php if($_SERVER['PHP_SELF'] === 'about.php'): ?>
<p> Show this in about.php </p>
<?php endif; ?>
</body>
</html>
Now, all you have to do is ... include foo.php in both pages.
Make the page you want and you can go about doing this:
<html>
<head>
<title>title</title>
<style type="text/css">
/* css goes here */
</style>
</head>
<body>
<div id="stay">I wont change</div>
<?php
if(basename($_SERVER['PHP_SELF'] == "other-page.php")){ ?>
<div id="change">I will change</div>
<?php }else{ ?>
<div id="change">Original div</div>
<?php } ?>
</body>
</html>
That takes the file name and based on that you can change content (if is only for one page, otherwise write a function/class based on that).
There are many ways to do this. Here are two, each with their own advantages and disadvantages.
Firstly, if you don't want to modify the page at all, you can add a small PHP code segment which will include a page passed in through the GET variable. For example
<html>
<head>
<title>title</title>
<style type="text/css">
/* css goes here */
</style>
</head>
<body>
<div id="stay">I wont change</div>
<div id="change"><?php require($_GET['page']); ?></div>
</body>
</html>
would mean that using the URL mypage.php?page=home.php would automatically include the contents of a file called home.php into that div.
Another way to do it is to divide up that page into 2 sections, and including both of them in any other page you use. For example, splitting the code into 2 seperate files, such as
top.php:
<html>
<head>
<title>title</title>
<style type="text/css">
/* css goes here */
</style>
</head>
<body>
<div id="stay">I wont change</div>
<div id="change">
bottom.php:
</div>
</body>
</html>
then in your PHP file you can use the following
require("top.php);
MY CONTENT HERE
require("bottom.php);
remember that you will need to use echo to output html code on this method if it is within <?php and ?> tags
hope this helps.
You can't do this will plain HTML.
To do it in php, first create template file like so: (template.php)
<html>
<head>
<title>title</title>
<style type="text/css">
* css goes here */
</style>
</head>
<body>
<div id="stay">I wont change</div>
<div id="change"><?=$main_content?></div>
</body>
</html>
Now, let's say you want to make a "contact me" page.
<?php
// in contact.php
$main_content = "Contact me at my#email.com
include "template.php";
?>
This will write the contents of template.php to the page and echo out the value of $main_content inside div#change
Now, this is generally frowned upon because managing your variables becomes difficult as the size of the template increases. To keep things sane, use a templating engine as all of the other answers are suggesting.