Silverstripe 3.4 load content via ajax / Shortcode issue - ajax

Shortcodes dont render correctly.
I am loading content via ajax into bootstrap-tabs.
calling ajax works.
routes are ok.
I've tried renderWith(), customise() ....
No matter what i try, the shortcodes don't render. Please help.
class EventPage_Controller extends Page_Controller {
public function EventDetail(SS_HTTPRequest $request){
if($request){
$group = DataObject::get_one('Group', "\"Code\" = 'eventgroup'");
$member = Member::currentUser();
if($member && $member->inGroup($group->ID)){
if($event = DataObject::get_by_id('Event', intval($request->param('eventID')))){
$eventDetail = array(
'EventTitle' => $event->Name,
'EventContent' => $event->Content
);
/* if( Director::is_ajax() ) {
return $this->renderWith('EventDetail', json_encode(array('EventContent' => $event->Content)));
}*/
//return $this->customise($eventDetail)->renderWith(array('EventDetail', 'Page'));
//echo $event->Content;
echo json_encode(array('error' => '0', 'EventContent' => $event->Content));
}
}
}
}
javascript:
$('#event-detail').hide();
$('.event-detail-btn').on('click', function(e){
//alert('click');
e.stopPropagation();
e.preventDefault();
if($(this).parent().is('tr')){
//alert('TR');
var eventID = $(this).parent().attr('id').split('_')[1];
var dateID = $(this).parent().attr('id').split('_')[2];
//alert(eventID + '_' + dateID);
getEventDetail(eventID, dateID);
}
$('#event-detail, #member-enrolment').toggle();
});
function getEventDetail(eventID, dateID){
//$('#eventDetail').load('Enrolment/EventDetail/'+ eventID + '/' +dateID);
$.ajax({
type: "POST",
url: 'Enrolment/EventDetail/'+ eventID + '/' +dateID,
dataType: "json"
}).success(function(msg){
$('#eventDetail').html(msg.EventContent);
});
}
Page.ss
<div id="enrolments" class="tab-pane fade">
<% include EventDetail %>
<% include MemberEnrolments %>
</div> <!--end enrolments-->
EventDetail.ss
<div id="event-detail">
<br><br>
<button type="button" class="event-detail-btn btn btn-default btn-sm">zurück</button>
<br><br>
<div id="eventDetail"></div>
<button type="button" class="event-detail-btn btn btn-default btn-sm">zurück</button>
</div>

Shortcodes are not automatically rendered when you're not calling them from a template, try:
$eventDetail = array(
'EventTitle' => $event->Name,
'EventContent' => $event->Content->forTemplate() //this is a HTMLText
);
or on SS3.4:
$eventDetail = array(
'EventTitle' => $event->Name,
'EventContent' => $event->Content->RAW() //this is a HTMLText
);
If this still doesn't work you might do it the hard way and call ShortcodeParser manually:
ShortcodeParser::get_active()->parse($event->Content);
Also, you might use Director::is_ajax() to check if it's really an ajax call and output the ajax response or - as a fallback - the whole page including ajax content. See lessons or docs

Related

How to forceUpdate vue data

I am using vuejs with laravel and I have links for next and previous pages while url is changing but new data won't show.
Code
Controller
$verse = Chapter::where('slug', $slug)->with(['verses', 'book'])->first();
$next = Chapter::where('id', '>', $verse->id)->first();
$previous = Chapter::where('id', '<', $verse->id)->first();
return response()->json([
'verses' => $verse,
'next' => $next,
'previous' => $previous,
]);
component
<div v-if="previous !== null" :v-model="previous" class="bible-nav-button previous">
<router-link :to="`/${testament_slug}/${book_slug}/${previous.slug}`">
<i class="fas fa-chevron-left"></i> <span>Previous</span>
</router-link>
</div>
<div v-if="next !== null" :v-model="next" class="bible-nav-button next">
<router-link :to="`/${testament_slug}/${book_slug}/${next.slug}`">
<span>Next</span> <i class="fas fa-chevron-right"></i>
</router-link>
</div>
<script>
export default {
name: "books",
data() {
return {
url: window.location.origin + "" + window.location.pathname,
title: '',
testament_slug:'',
book_slug: '',
slug: '',
verses: [],
next: '',
previous: ''
}
},
methods: {
getBooks: function(){
this.testament_slug = this.$route.params.testament_slug
this.book_slug = this.$route.params.book_slug
this.slug = this.$route.params.slug
axios.get('/api/'+this.$route.params.book_slug+'/'+this.$route.params.slug+'/'+this.$route.params.slug).then((res) => {
this.verses = res.data.verses
this.title = "Read Bible: " +res.data.verses.book.name+ " " +res.data.verses.name
this.next = res.data.next
this.previous= res.data.previous
})
.catch((err) => {
console.log(err)
});
},
myHTML: function(item) {
return "<strong>"+item.number+"</strong> "+item.body+" ";
}
},
mounted() {
this.getBooks();
}
}
</script>
Any idea how i can fetch my new data?
You can use :key props in <router-view> tag and use the route fullpath.
<router-view :key="$route.fullPath"></router-view>
I used to put a watcher of the current route and call function to fetch data, but I just found that we can do this after watching vue-router tutorial from vueschool.
Also see the answer of this question
You have two simple options:
1) Change the "previous" and "next" to #click actions that call the fetch function again and then update the URL (like this this.$router.push()).
<span #click="goNext(/* needed arguments here */)">Next</span>
goNext (/* params here */) {
//set whatever variables you need to
this.$router.push(/* route as string here */)
this.getBooks()
}
2) Since you're using the router, use guards to update every time the URL changes:
https://router.vuejs.org/guide/advanced/navigation-guards.html
beforeRouteUpdate(to, from, next) {
this.getBooks()
next()
}

Post 403 forbidden on Yii2 Ajax Call

I know there's other topic on this in stackoverflow but it still didn't work for me. I try to make a simple dynamic menu that generate dynamic content based on the chosen <li> id.
This is the code to generate the menu :
foreach($cabang as $index=>$model){
echo '<li id='.$model->idDpd->id_dpd.'>
<a class="nav-link" href="#" role="tab" data-toggle="tab">'.$model->idDpd->dpd.'</a>
</li>';
}
The menu is created successfully. But I have the problem with the content generated with Ajax
This is what I have in my view file :
$script = <<< JS
$(document).ready(function(){
function load_page_details(id)
{
$.ajax({
url: "<?=Url::to(['/site/fetch']) ?>",
method:"POST",
data:{id:id}, //pass the 'id' of Load_page_details function parameter to the targeted URL
success:function(data)
{
$('#page_details').html(data);
}
});
}
//load page-details where the id in the database table equals 1. Set the default to 1 while page is loading for the first time.
/* load_page_details(1);*/
$('.nav li').click(function(){
var page_id = $(this).attr("id");
load_page_details(page_id);
});
});
JS;
$this->registerJs($script)
?>
This is my SiteController and the action :
public function actionFetch(){
if (Yii::$app->request->isAjax) {
// fetch the $_POST["id"]
$data = Yii::$app->request->post('id');
if(isset($data))
{
$query= Cabang::find()->where(['id_dpd'=> $data])
->joinWith('idDpd')
->all();
$output = '';
foreach($query as $model)
{
$output .= '
<div role="tabpanel" class="col-lg-4 tab-pane fade show active" >
<div class="col-md-12">
<h4>'.$model->kota.'</h4>
<p>'.$model->alamat.'</p>
<p>'.$model->telp.'</p>
<p>'.$model->email.'</p>
<p>'.$model->jadwal.'</p>
</div>
</div>
';
}
/* echo $output;*/
// return Json
return \yii\helpers\Json::encode($output);
}
}
}
The error caught in my console in chorome dev tool : jquery.js:9175 POST http://localhost/%3C?=Url::to([%27/site/fetch%27])%20?%3E 403 (Forbidden)
I tried to make the fetch function to a new php file and link the URL in my Ajax to that file (not to a controller or SiteController in my case) like : url: url:"site/fetch.php",but it returned jquery.js:9175 POST http://localhost/site/fetch.php 404 (Not Found)
What am I doing wrong? I have spent two days without solution. Thanks for the help!
Your PHP is not correct - you cannot use <?= /* ... */ ?> inside of heredoc. You need to use temporary variable:
$url = Url::to(['/site/fetch']);
$script = <<<JS
$(document).ready(function () {
function load_page_details(id) {
$.ajax({
url: "$url",
method: "POST",
data: {id: id}, //pass the 'id' of Load_page_details function parameter to the targeted URL
success: function (data) {
$('#page_details').html(data);
}
});
}
$('.nav li').click(function () {
var page_id = $(this).attr("id");
load_page_details(page_id);
});
});
JS;
$this->registerJs($script);

Why the if condition does not filtering the results?

I want to create advance search filtering staff data according to certain criteria chosed by users. This application developed using laravel 5. I am querying the data using ajax function and if statement to filter the criteria. The results appear but it does not filter any condition in the if statement.
The controller of the filtering condition is this:
public function kakitangan(Request $request)
{
$query = DB::table('itemregistrations')
->select('itemregistrations.ItemRegistrationID','itemregistrations.name', 'itemregistrations.Nobadan');
if ($request->section != ""){
$query->where('SectionID', $request->section);
}
$newitem = $query->get();
return response::json($newitem);
}
I also have tried this:
$query = DB::table('itemregistrations')
->select('itemregistrations.ItemRegistrationID','itemregistrations.name', 'itemregistrations.Nobadan');
if(request('section')) {
$query->where('SectionID', request('section'));
}
$newitem = $query->get();
return response::json($newitem);
But the result is the same..all data in itemregistrations appear in the output page. Although I select another section criteria.
This is the view page code for selection:
<div class="row">
<div class="col-lg-2">
{{ Form::label('Seksyen', 'Seksyen') }}
</div>
<div class="col-lg-2">
{{ Form::select('section', $sections, '', ['class' => 'form-control select2', 'placeholder' => '--pilih--']) }}
</div>
</div>
</div>
The selection id is from controller function:
$sections = Section::pluck('sectionname', 'SectionID');
//sent to html view
return view('carian.index', compact('sections'));
Button to call ajax function to get the query:
<button class="btn btn-primary btn-md" id="cari">Cari</button>
The code for results appear:
<script type="text/javascript">
$( "#cari" ).click(function() {
var seksyen = $("#section").val();
$.ajax({
url: '{{ url('kakitangan') }}',
data: {'section': seksyen},
dataType: 'json',
success: function (data) {
console.log(data);
$('#datatable tr').not(':first').not(':last').remove();
var html = '';
for(var i = 0; i < data.length; i++){
html += '<tr>'+
'<td>' + data[i].name + '</td>' +
'</tr>';
}
$('#datatable tr').first().after(html);
},
error: function (data) {
}
});
});
</script>
Should be when the user select a section, only staffs of the section appear. But now all staffs appear when select any section.
I just tried to test whether the section value is correctly passed to the controller using this in controller:
$try=$request->input('section');
return response::json($try);
It results empty array..no value passed? Is it the section value is not passed correctly? How to correct this problem?
You are passing the section as a post param while you performing a GET request.
Using jQuery you can send this as a query string using:
var seksyen = $("#section").val();
$.ajax({
url: '{{ url('kakitangan') }}?' + $.param({'section': seksyen}),
dataType: 'json',
...
In your controller you can also explicitly check if a request contains a query string using the has method on a request
if(request()->has('section')) {
$query->where('SectionID', request('section'));
}
EDIT:
using the laravel collective Form helpers you can specific the field id using the following (note the fourth argument id)
{{ Form::select('section', $sections, '', ['id' => 'section', 'class' => 'form-control select2', 'placeholder' => '--pilih--']) }}

Laravel 5.4 - Populate dropdown based on another dropdown selected value

I want when select one value from first dropdown to automatcly populate another dropdown based on first dropdown value.
My view:
<label for="category">Catégorie(s):</label>
{!! Form::select('category', $category,null, array('class' => 'form-
control')) !!}
<label for="brand">Marque:</label>
{!! Form::select('brand_name', $brand_name,null, array('class' => 'form-control')) !!}
My controller:
public function index()
{
$category = Category::pluck('categoryName', 'id');
$brand = Brand::pluck('brandName', 'id');
return view ( 'site.indexS',compact('brand','category') );
}
How to populate another dropdown? Any idea?
you can easily do it with a little bit of ajax and get method. May be you are trying to load brand depend on category lets roll :
Your controller:
public function index()
{
$category = Category::pluck('categoryName', 'id');
// no need to query brand here because we will load it depend on category
$brand = [];
return view ( 'site.indexS',compact('brand','category') );
}
// here we are adding another method in your controller which will return brand object depend on category id
public get_brand($categpry_id){
// hope your brand table contain category_id or any name as you wish which act as foreign key
$brands= Brand::where('category_id',$category_id)
->pluck('brandName','id');
return json_encode($brands);
}
Now in route we need to add this to hit this url :
Route::get('get-brand','YourControllerName#get_brand');
In view :
{{-- i am adding id for both dropdown --}}
Catégorie(s):
{!! Form::select('category', $category,null, array('id' => 'category_dropdown','class' => 'form-
control')) !!}
<label for="brand">Marque:</label>
{!! Form::select('brand_name', $brand_name,null, array('id' => 'brand_dropdown','class' => 'form-control')) !!}
now in our view file we need to use ajax, there is many other way i am preferring ajax here
<script type="text/javascript">
var url = "{{url('/')}}";
</script>
<script type="text/javascript">
$('#category_dropdown').on('change', function() {
$('#brand_dropdown').empty();
var id = $('#category_dropdown').val();
$('#brand_dropdown').html('<option selected="selected" value="">Loading...</option>');
var url = url + '/get-brand/'+id;
$.ajax({
url: url,
type: "GET",
dataType: "json",
success:function(data) {
//console.log(data);
$('#brand_dropdown').html('<option selected="selected" value="">Select Brand</option>');
$.each(data, function(key, value) {
$('#brand_dropdown').append('<option value="'+key+'">'+value+'</option>');
});
}
});
});
</script>

How to update pagination template of knppaginatorbundle after ajax query

Im using knppaginatorbundle to create pagination. I have created a jquery code to select data with ajax.
Everything is okay when I click on the page number , the content is loaded with the correct data.
But I have a problem , The pagination template is not changed after after ajax query:
previous and next links values must changed
current page must be disabled
and other changes that need to be done ...
How can I do this ?
public function listAction($page, Request $request)
{
$em = $this->getDoctrine()->getManager();
$paginator = $this->get('knp_paginator');
$qb = $em->getRepository('AppBundle:Travel')->getListTravels();
$pagination = $paginator->paginate(
$qb, $request->query->get('page', $page), 3
);
//ajax request
if ($request->isXmlHttpRequest()) {
$view = $this->renderView('#App/Frontend/Travel/list.html.twig', array(
'pagination' => $pagination
));
$response = new JsonResponse(array('ok' => $view));
return $response;
}
return $this->render('AppBundle:Frontend/Travel:travel-list-view.html.twig', array(
'pagination' => $pagination,
));
}
I have added an attr data-target to pagination template like this:
<a data-target="{{ page }}" href="{{ path(route, query|merge({(pageParameterName): page})) }}">{{ page }}</a>
View
//.....
<div id="mydiv">
// list.html.twig contains the loop
{% include "AppBundle:Frontend/Travel:list.html.twig" %}
</div>
<br>
{{ knp_pagination_render(pagination) }}
//....
<script>
$(document).ready(function () {
$("ul#pagination a").click(function (e) {
e.preventDefault();
var dataTarget = $(this).attr("data-target"); // each <a> has attr named data-target contains num of page
var hash;
hash = 'page=' + dataTarget;
window.location.hash = hash;
if (window.location.hash != "") {
$.ajax({
type: 'get',
dataType: 'json',
url: Routing.generate('frontend_travels_list', {'page': dataTarget}),
success: function (msg) {
if (msg["ok"] === undefined) {
alert('error');
} else {
$("#mydiv").html(msg["ok"]);
}
}
});
}
});
});
</script>
Route
frontend_travels_list:
path: /travels/{page}
defaults: { _controller: AppBundle:TravelFrontend:list, page: 1 }
options:
expose: true
If someone else needs a solution there 2 ways.
You can use that bundle https://github.com/nacholibre/knppaginator-ajax
You should build new pagination string in controller and send it in JsonResponse as a param. Then replace pagination element in DOM via jQuery on success.
For SF 4.3 you can use my approach
To be able to inject the Processor in controller you have to add alias for autowiring in services.yaml
Knp\Bundle\PaginatorBundle\Helper\Processor: '#knp_paginator.helper.processor'
Based on injected PaginatorInterface you should build your $pagination object (PaginationInterface)
Use Processor to build the context array for Twig.
$paginationContext = $processor->render($pagination);
render method expects SlidingPagination object, but got $pagination which is PaginationInterface - however it seems that is ok
Get the Twig and render a final string
$twig = $this->get('twig');
$paginationString = $twig->render($pagination->getTemplate(), $paginationContext);
Example of working controller
if ($request->isXmlHttpRequest()) {
$view = $this->render('#App/Frontend/Travel/list.html.twig', array(
'pagination' => $pagination
))->getContent();
$paginationContext = $processor->render($pagination);
$twig = $this->get('twig');
$paginationHtml = $twig->render($pagination->getTemplate(), $paginationContext);
$response = new JsonResponse(['view' => $view, 'paginationHtml' => $paginationHtml]);
return $response;
}
then in jQuery
success: function (msg) {
if (msg["ok"] === undefined) {
alert('error');
} else {
$("#mydiv").html(msg["view"]);
$("#myDivContainingPagination").html(msg["paginationHtml"])
}
}

Resources