Render View inside a layout view in yii2 - php

I need to make a search form, which will display on all pages, even the error pages, on the top of the page, so i decided to make a view and model for it, and render this view in the main layout.So i have created a simple model:
SearchModel.php
<?php
namespace app\models;
use Yii;
use yii\base\Model;
class SearchFormModel extends Model
{
public $query;
public function rules()
{
return [
];
}
}
And a view:
SearchView.php
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
$form = ActiveForm::begin([
'id' => 'search-nav-form',
'options' => ['class' => 'form-inline ml-3'],
]) ?>
<div class="input-group input-group-sm">
<?= $form->field($model, 'text')->textInput(['class' => 'form-control form-control-navbar', 'placeholder'
=> 'Search'])->label('Search'); ?>
<div class="input-group-append">
<button class="btn btn-navbar" type="submit">
<i class="fa fa-search"></i>
</button>
</div>
</div>
<?php ActiveForm::end() ?>
Which is a search form. Now i have also the main layout:
<?php
use app\widgets\Alert;
use yii\helpers\Html;
use yii\bootstrap\Nav;
use yii\bootstrap\NavBar;
use yii\widgets\Breadcrumbs;
use app\assets\AppAsset;
AppAsset::register($this);
?>
<?php $this->beginPage() ?>
<!DOCTYPE html>
<html lang="<?= Yii::$app->language ?>">
<head>
<meta charset="<?= Yii::$app->charset ?>">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<?php $this->registerCsrfMetaTags() ?>
<title><?= Html::encode($this->title) ?></title>
<?php $this->head() ?>
</head>
<body>
<?php $this->beginBody() ?>
<div class="wrap">
<div class="container">
<?= Breadcrumbs::widget([
'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],
]) ?>
<?= Alert::widget() ?>
<?= $content ?>
</div>
</div>
<footer class="footer">
<div class="container">
<p class="pull-left">© My Company <?= date('Y') ?></p>
<p class="pull-right"><?= Yii::powered() ?></p>
</div>
</footer>
<?php $this->endBody() ?>
</body>
</html>
<?php $this->endPage() ?>
What i dont understand is, how i can render my search form from inside my layout view? I need to put it in controller, but controller only gives actions for specific page routes.
UPDATE
I got rid of all errors but now the form is just not rendering on the page, there is no form tag even. Here is how i render it inside main.php:
$model = new SearchFormModel;
$this->render('#app/views/site/SearchFormView',['model' => $model]);
And i have fixed the model SearchFormModel.php like this:
class SearchFormModel extends Model
{
public $search;
public function rules()
{
return [
// тут определяются правила валидации
];
}
}

You can render a view inside a layout file using
<?= $this->render('//layouts/path/to/view') ?>
<?= $this->render('#app/views/path/to/view') ?>
or
<?= Yii::$app->view->renderFile('#app/views/path/to/view.php'); ?>
See DOCS for render() and renderFile()

Render function in Yii2 returns the result of rendering. You have to echo explicitly. Try out instead:
$model = new SearchFormModel;
echo $this->render('#app/views/site/SearchFormView',['model' => $model]);

You should extract your form into widget and use it in your layout. Layouts should be relatively simple, including some external view into it looks like code smell, and creating model inside of view file (including layouts files) is basically a violation of MVP pattern.
Create widget with form:
class SearchFormWidget extends \yii\base\Widget {
public function run() {
$model = new SearchFormModel();
$model->load(Yii::$app->request->get());
return $this->render('search-form-widget', ['model' => $model]);
}
}
Put view with your form in widgets/views/search-form-widget.php (or similar path depending where you put widget class), and use widget inside of layout:
<?= SearchFormWidget::widget() ?>
In similar way you may use it in any other place. Much more clean and safe approach than including views viles directly.

Related

I want to ask about custom widget in Yii2 advanced template

I have created a custom widget on my yii2 advanced project
I create new dir name components in backend dir
after that, I create new dir again in components dir name views
in backend/components I create new PHP file name SideBWidget.php
<?php
namespace backend\components;
use yii\base\Widget;
use yii\helpers\Html;
use common\models\Content;
class SideBWidget extends Widget{
public function run(){
$models = Content::findAll([
'c_pkey'=>0,
]);
$this->render('sideb',[
'model' => $models
]);
}
}
?>
in backend/components/views I create sideb.php
<div id="sidebar-nav" class="sidebar">
<div class="sidebar-scroll">
<nav>
<ul class="nav">
<?php foreach($model as $row): ?>
<li><i class="lnr lnr-alarm"></i> <span><?php echo $row->c_name; ?></span></li>
<?php endforeach; ?>
</ul>
</nav>
</div>
</div>
and I call the widget in views/layout/main.php like this, and I also use the widget path
use backend\components\SideBWidget;
<?= SideBWidget::widget() ?>
but when I run there is nothing and no error message. Where is the problem?
You must add return statement in run() function of widget:
return $this->render('sideb',[
'model' => $models
]);

Yii RenderPartial not working

I am using renderParial() function to render views->subscriber->_form from views->layouts->main.php
Problem i am getting is I am failed to insert data using this. Gii generated CRUD is working perfectly but when i render _form and want to insert data in database it's not working.
Here is my code.
main.php
<div class="col-lg-6" style="text-align:right;">
<span>Subscribe Newsletter</span>
<div style="float:right;margin-left:10px;">
<?php
$model=new Subscription();
$this->renderPartial("/subscription/_form",array('model'=>$model));?>
</div>
and _form.php
<?php
/* #var $this SubscriptionController */
/* #var $model Subscription */
/* #var $form CActiveForm */
?>
<div class="form">
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'subscription-form',
// Please note: When you enable ajax validation, make sure the corresponding
// controller action is handling ajax validation correctly.
// There is a call to performAjaxValidation() commented in generated controller code.
// See class documentation of CActiveForm for details on this.
'enableAjaxValidation'=>false,
)); ?>
<?php echo $form->errorSummary($model); ?>
<div class="row">
<?php echo $form->textField($model,'email',array('size'=>30,'maxlength'=>30,'placeholder'=>'Email Address')); ?>
<?php echo $form->error($model,'email'); ?>
<?php echo CHtml::submitButton($model->isNewRecord ? 'Subscribe' : 'Save',array('class'=>'btn btn-xs btn-success subscribeBtn')); ?>
</div>
<?php $this->endWidget(); ?>
</div>
As adamS and Michiel have commented, if you want to put a form or data in your main.php layout file, you should use a widget.
To create a widget, you need to do the following:
1: Create a php file in your /protected/components/ dir, something like SubscriptionWidget.php
2: Create a dir views in your components dir
3: Create your view .php file in your /protected/components/views/, something like subscriptionWidget.php
4: Put the following code in your SubscriptionWidget.php file:
<?php
class SubscriptionWidget extends CWidget
{
public function init()
{
}
public function run()
{
$model = new SubscriptionForm;
if(isset($_POST['SubscriptionForm']))
{
// proces the data
}
$this->render('subscriptionWidget', array('model'=>$model));
}
}
?>
Your widget is done. All you need to do now is call it in your main.php layout file, like so:
<!doctype html>
<html lang="en">
...
<?php $this->widget('SubscriptionWidget'); ?>
...
</html>
Also, don't forget to put the form in your newly created view file.
Hope this helps.
Try adding one more slash
$this->renderPartial("//subscription/_form",array('model'=>$model));

codeigniter, Cant pass the data on view page from the controller page

I am new to CodeIgniter and have a problem I have been unable to figure out. Here is my model class (filename = tenant.php):
<!-- language php -->
class tenant extends CI_Model {
function getTenants() {
$this->db->select()->from('hrs_tenants');
$query=$this->db->get();
return $query->result_array();
}
}
my controller class (filename = tenants.php):
<!-- language php -->
class tenants extends CI_Controller {
function index() {
$this->load->model('tenant');
$data['tenants']= $this->tenant->getTenants();
echo "<pre>"; print_r($data['tenants']); echo "</pre>";
$this->load->view('tenants', $data);
}
}
and finally my view file (tenants.php):
<!-- language php -->
<html>
<head>
<title>Tenants Listing</title>
</head>
<body>
<h1>Tenants Listing</h1>
<?php
if(!isset($tenants)) {
?>
<p>There are no Tenants to List</p>
<?php
} else {
foreach($tenants as $row){?>
<h2><?php $row['T_Name']?></h2>
<p>Mobile : <?php $row['T_Mobile']?></p>
<?php
}
}
?>
</body>
</html>
Now coming back to the problem - it should display the tenant name and tenant mobile no., but the view doesn't display it. Instead it shows the static HTML view. But some how it do repeat the tags. Here is the html output/ rendered HTML for the view file:
<pre>Array
(
[0] => Array
(
[T_ID] => 1
[T_Name] => John Doe
[T_Mobile] => 030112345678
)
[1] => Array
(
[T_ID] => 2
[T_Name] => Haider Hassan
[T_Mobile] => 033412345678
)
)
</pre><html>
<head>
<title>Tenants Listing</title>
</head>
<body>
<h1>Tenants Listing</h1>
<h2></h2>
<p>Mobile : </p>
<h2></h2>
<p>Mobile : </p>
</body>
</html>
My database is connected fine, as I also did an echo directly in the controller file and it is also generated in the HTML file within pre tag.
Did I forgot to add something, why am I running into this issue?
Controller file:
class tenants extends CI_Controller {
function index() {
$this->load->model('tenant');
$data['tenants']= $this->tenant->getTenants(); //Get rid of Echo
$this->load->view('tenants', $data);
}
}
View file:
<html>
<head>
<title>Tenants Listing</title>
</head>
<body>
<h1>Tenants Listing</h1>
<?php
if(!isset($tenants)) {
echo '<p>There are no Tenants to List</p>';
} else {
foreach($tenants as $row): ?>
<h2><?= $row['T_Name'] ?></h2>
<p>Mobile : <?= $row['T_Mobile'] ?></p>
<?php endforeach;
}
?>
</body>
</html>
Yea doing echo is cool. Not a problem. But, try to minimize the use of closing php tag... Try to concat strings rather opening php after every break...
Questions?
i think the only solution is now to write echo with every $row
i did it now like this
<h2><?php echo $row['T_Name']?></h2>
<p>Mobile : <?php echo $row['T_Mobile']?></p>
is this ok to write echo everywhere or is there any better solution?

Display two views at once and change url on change

I have a main view with a menu which helps me display another view. It's similar to this:
<div id="page">
<div id="menu">
Page1
Page2
</div>
<div id="content">
<!-- Page1 or Page2 are displayed here -->
</div>
</div>
I'm using php's Yii framework. Which makes me not to use <?php include("menuview.php"); ?>. So I'm looking for a different solution. I can do this with Ajax, but I would also like the link to change to mypage/controller/Page2. With Ajax I can only get it to this: mypage/controller/index#Page2
in main view, instead of include do
<?php echo $this->renderPartial('_page1', array('model'=>$model)); ?>
UPDATE:
protected/views/controller/page1.php and protected/views/controller/page2.php content at your liking
protected/views/layouts/custom.php:
<?php $this->beginContent('//layouts/main'); ?>
<div id="page">
<div id="menu">
<?php echo CHtml::ajaxLink('Page1', array('controller/page1'), array('update' => '#content')); ?>
<?php echo CHtml::ajaxLink('Page2', array('controller/page2'), array('update' => '#content')); ?>
</div>
<div id="content">
<?php echo $content; ?>
</div>
</div>
<?php $this->endContent(); ?>
protected/controllers/ControllerController.php:
class ControllerController extends Controller {
/**
* #var string the default layout for the views.
*/
public $layout = '//layouts/custom';
public function actionPage1() {
if (Yii::app()->request->isAjaxRequest)
$this->renderPartial('page1');
else
$this->render('page1');
}
public function actionPage2() {
if (Yii::app()->request->isAjaxRequest)
$this->renderPartial('page2');
else
$this->render('page2');
}
}
UPDATE2:
If you need the link in address bar to change too then your only option is to use regular link and not ajax <?php echo CHtml::link('Page1', array('controller/page1')); ?>
using ajax the preferred way is using hash like you mentioned.

I'm forced to call a controller method from a view, how do I refactor my code?

Okay so, I'm working with CodeIgniter. posts.php is my view that displays all the posts, each post must display its corresponding comments, which is what I'm trying to achieve.
I have a method in my model that takes the postid($postid) and return its corresponding comment($comment), unless I call the model method via a controller method,how do I accompolish this?
This is my view :
<body>
<?php foreach ($post as $key):?>
<div class="container">
<div class="span10">
<div id="box" class="alert-message block-message info">
<div id="post" class="post">
<?php echo $key->content;?><br />
</div>
<div>
<p><?php //echo $comment;?></p> <!--HERE THE COMMENTS OF THE CORRESPONDNING POST MUST BE ECHOED-->
</div>
<div>
<p><em>Comment</em></p>
</div>
<div id="commentarea<?php echo $key->postid;?>">
<?php $name=array('name'=>"form$key->postid");
echo form_open("/welcome/comments/$key->postid",$name);
$data=array(
'id' => 'input',
'name'=> 'content',
'rows' => '2',
'placeholder' => "Write a comment...",
'autofocus' => 'TRUE'
);
echo form_textarea($data);
?>
Comment
<?=form_close();?>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$(function(){
$("div#commentarea<?=$key->postid;?>").hide();
$('a#commentnow<?=$key->postid;?>').click(function(){
$("div#commentarea<?=$key->postid;?>").slideToggle(250);
});
});
</script>
<?php endforeach;?>
</body>
This is my controller method that returns the comments that corresponds to the postid:
public function comments($postid)
{
//Post Comment
$comment=$this->input->post('content');
$data=array('content'=>$comment,'comment_postid'=>$postid);
$this->comments->postcomment($data);
//Retrieve
$comments['comment']=$this->comments->retrieve($postid);
$this->load->view('posts',$comments);
}
I'm a newbie,pardon me if my code is bad. I'm always looking forward to improving my code> Thanks for being patient. :)
Looking at your code it seems to me that you haven't fully understood how to use the MVC.
Firstly, your controller method comments contains the extraction of comments AND adding comments to a post. This doesn't seem logical when taking a look at the view file.
Instead you should seperate those two.
In your controller, add another metod called *post_comment* and move the adding comment functionality to that method and add a redirection afterwards:
public function post_comment($postid)
{
//Post Comment
$comment=$this->input->post('content');
$data=array('content'=>$comment,'comment_postid'=>$postid);
$this->comments->postcomment($data);
redirect('welcome/comments'); //redirect back to comments
}
Now, remove the adding of a comment from your comment method in the controller, so that you only retrieve the comments:
public function comments($postid)
{
//Retrieve
$comments['comment']=$this->comments->retrieve($postid);
$this->load->view('posts',$comments);
}
And finally change your view file - you need to post the comment to a new URL:
<?php $name=array('name'=>"form$key->postid");
echo form_open("/welcome/post_comment/$key->postid",$name);
This should do the trick.

Categories