I have this list of things generated from an array, where the array value maps to the array key, which maps to a query in the database. Now the problem I'm facing is that when this list is included in my ajax portion, it only works for one click before the page refreshes. What gives?
I'm using the HTML5 History API method to change the url upon clicks by the href="" portion of the link.
I'm somewhat new to jQuery, which is odd since I'm a front end developer primarily but I just never got the time to catch up, but my link list breaking this code just doesn't make sense to me.
$("a[rel='ajax']").click(function(e){
//e.preventDefault();
pageurl = $(this).attr('href');
$.ajax({url:pageurl+'?rel=ajax',success: function(data){
$('#ajax')
.load(pageurl + ' #resultati');
}});
if(pageurl!=window.location){
window.history.pushState({path:pageurl},'',pageurl);
}
return false;
});
The links are generated using this function in PHP, I'm using the laravel framework if that makes any difference.
public static function filterlink ($filter, $what)
{
if (URI::segment(2) == 'make')
{
$first = URI::segment(3);
$next = URI::segment(4);
}
else
{
$first = URI::segment(2);
$next = URI::segment(3);
}
// what == 0 is the filter, what == 1 is the +filter. This reffers to the link being created.
switch (substr($first, 0, 1))
{
case ' ': // example.ex/make/[+]current starts with a plus sign.
if($what == 0)
//new no+ filter.
{
return HTML::link('make/'.self::slug($filter.'/'.$first), $filter, array('rel' => 'ajax'));
// example.ex/make/+current => example.ex/make/newfilter/+current
}
elseif($what == 1)
//new +filter
{
return HTML::link('make/+'.self::slug($filter), $filter, array('rel' => 'ajax'));
// example.ex/make/+current+replaced+by+newfilter
}
break;
default:
if($what == 0)
// new no+ filter.
{
if(!empty($next))
{
return HTML::link('make/'.self::slug($filter.'/'.$next), $filter, array('rel' => 'ajax'));
}
else
{
return HTML::link('make/'.self::slug($filter), $filter, array('rel' => 'ajax'));
}
}
elseif($what == 1 && (!empty($first)))
{
return HTML::link('make/'.self::slug($first.'/+'.$filter), $filter, array('rel' => 'ajax'));
}
elseif($what == 1 && (empty($first)))
{
return HTML::link('make/+'.self::slug($filter), $filter, array('rel' => 'ajax'));
}
}
}
I've tried putting my link lists outside the ajax field, which keeps the ajax flow going without any boring page refreshes, but my link urls don't update, obviously, and I'm only able to construct one-ended links, breaking the pages dual filter functionality.
Any help would be great.
If you're actually loading HTML content with links that you want to be AJAX friendly, then you'll need to use .on so that the new links also get taken over by your jQuery function.
$(document).on('click',"a[rel='ajax']",function(e) {
Working sample here:
http://jsfiddle.net/hansvedo/cJW54/
Just a quick thought, what about placing preventDefault where the pushState function is? Or even just uncommenting it where it is? preventDefault prevents the normal linking action from happening.
if(pageurl!=window.location){
e.preventDefault();
window.history.pushState({path:pageurl},'',pageurl);
}
Related
I have a very simple ng-if construction using two MD buttons and one AngularJS scope variable isPlaying. However, the ng-if doesn't seem to work along with the variable. I can see the variable changing as I click the buttons, using console tools, however no changes to the DOM. Strangely enough the ng-if does seem to trigger when I hover other Angular components, such as buttons in the main nav.
HTML/MD/PHP:
<md-button class="md-icon-button" ng-if="!isPlaying" ng-click="play()" aria-label="Play">
<md-icon md-svg-src="<?php echo get_stylesheet_directory_uri(); ?>/img/icon/ic_play_arrow_black_24px.svg"></md-icon>
</md-button>
<md-button class="md-icon-button" ng-if="isPlaying" ng-click="pause()" aria-label="Pause">
<md-icon md-svg-src="<?php echo get_stylesheet_directory_uri(); ?>/img/icon/ic_pause_black_24px.svg"></md-icon>
</md-button>
JS:
$scope.play = function () {
player.playVideo();
$scope.isPlaying = true;
}
$scope.pause = function () {
player.pauseVideo();
$scope.isPlaying = false;
}
The problem was being caused by a function wrapped inside a timeout block. I replaced the setTimeout with $timeout and everything started working fine:
$scope.isPlaying = false;
$scope.videoTime = 0;
function onPlayerStateChange() {
console.log(player);
if (player.getPlayerState() === 1)
$scope.isPlaying = true;
else
$scope.isPlaying = false;
$timeout(onPlayerStateChange, 500);
}
I created pagination and wanted to add check if user want to access page, which is not exisits. For example, there are 10 pages and user wants to open 999 page. I wanted to add error message, which will show, that there are no 999 page.
I tried this (and this worked):
public function listAction() {
$page = // getting page
$pagginator = // setting paginator
// this part will add message to the flashMessanger
if($page > $paginator->count()) {
$message = 'There are no such page';
$this->flashMessenger()->addMessage($message);
return $this->redirect()->toRoute('zfcadmin/news');
}
return new ViewModel(array(
'news' => $paginator,
));
}
This is working code. This is code for list action. This action is executed, when I type in browser this: example.com/admin/news. If I will type example.com/admin/news/page-500 browser will be redirected to example.com/admin/news and there will be message There are no such page.
I wanted to add same in other parts of my site and I got problem in index action of same controller. This is index action:
public function indexAction() {
return new ViewModel(array(
'news' => $this->getItems(),
'categoryName' => null,
));
}
As you see, I call function getItems(). Code of this function:
private function getItems($categoryId = null) {
$page = // getting page
$paginator = // getting paginator
if($page > $paginator->count()) {
$message = 'There are no such page';
$this->flashMessenger()->addMessage($message);
if($categoryId) {
return $this->redirect()->toRoute('news/category', array('category' => $categoryId));
} else {
return $this->redirect()->toRoute('news');
}
}
return $paginator;
}
I tried this and I got this error:
Fatal error: Call to undefined method
Zend\Http\PhpEnvironment\Response::count() in
F:\Server\domains\zf2-skeleton\module\News\view\news\news\index.phtml
on line 32
I realized, that it is because I returning $this->redirect as result of getItems() function and it is assigned to view variable news.
I tried this then:
if($page > $paginator->count()) {
$message = 'There are no such page';
$this->flashMessenger()->addMessage($message);
if($categoryId) {
$this->redirect()->toRoute('news/category', array('category' => $categoryId));
} else {
$this->redirect()->toRoute('news');
}
}
I am not getting any errors, but I am not getting message, that page is bad too.
I think... I bet, nobody here doesn't want to know what I think :)
Help me with this problem, please.
How to make redirect + write message to flashMessanger (so I can output it later) correctly in my case?
Update
I understand, that it is possible to return array from function get items and handle it. One of element will show should zf2 do redirect or not, another will show category id, third will containt paginator by itself, but it is dirty solution (but possible :( ).
I'm creating a new widget that allows custom text/HTML to be added to the page. I noticed that if you enter text containing double-quotes, the first occurrence of it and everything after gets cut off, so that you're missing data when you try to edit the widget again.
To make sure I didn't screw something up, I was able to verify this issue on a fresh install of Magento (1.7), by adding a stock widget -- Catalog Product Link -- to the page. If you set the Anchor Custom Text to something with double-quotes, insert, and edit again, you will see the text has been truncated.
I'm not sure where the problem occurs. The data is successfully written to the tinyMCE content element, but somehow gets malformed between there and an Ajax.Request call for the admin/widget/loadOptions route.
I found a related article here:
http://www.behrendt.io/2013/04/12/using-a-wysiwyg-editor-in-a-magento-widget/
The author mentions at the bottom a need for overriding a controller to use base64 encoding when transmitting data for widgets. This seems like it might work for me, but I wanted to be sure.
Here's a visual example of the problem I'm experiencing:
Anyone seen this before? Know where it comes from? How to fix? :) Thanks.
Looks like that article put me in the right direction, by overriding Mage_Widget_Adminhtml_WidgetController:
http://www.behrendt.io/2013/04/12/using-a-wysiwyg-editor-in-a-magento-widget/
I took his solution a step further and decided to encode ALL values when building the widget code:
# Namespace_Module_Adminhtml_WidgetController extends Mage_Widget_Adminhtml_WidgetController
public function buildWidgetAction()
{
$type = $this->getRequest()->getPost('widget_type');
$params = $this->getRequest()->getPost('parameters', array());
$asIs = $this->getRequest()->getPost('as_is');
if($type == 'namespace/module_widget')
{
foreach($params as $key => $value)
{
$params[$key] = base64_encode($value);
}
}
$html = Mage::getSingleton('widget/widget')->getWidgetDeclaration($type, $params, $asIs);
$this->getResponse()
->setBody($html);
}
This meant I also had to decode them when loading the widget for editing:
# Namespace_Module_Adminhtml_WidgetController extends Mage_Widget_Adminhtml_WidgetController
public function loadOptionsAction()
{
try {
$this->loadLayout('empty');
if( ($paramsJson = $this->getRequest()->getParam('widget')) )
{
$request = Mage::helper('core')->jsonDecode($paramsJson);
if(is_array($request))
{
$optionsBlock = $this->getLayout()->getBlock('wysiwyg_widget.options');
if(isset($request['widget_type']))
{
$optionsBlock->setWidgetType($request['widget_type']);
}
if(isset($request['values']))
{
if($optionsBlock->getWidgetType() == 'namespace/module_widget')
{
foreach($request['values'] as $key => $value)
{
$request['values'][$key] = base64_decode($value);
}
}
$optionsBlock->setWidgetValues($request['values']);
}
}
$this->renderLayout();
}
}
catch (Mage_Core_Exception $e)
{
$result = array('error' => true, 'message' => $e->getMessage());
$this->getResponse()
->setBody(Mage::helper('core')->jsonEncode($result));
}
}
And finally, in my widget block, I had to decode all data on-the-fly:
# Namespace_Module_Block_Widget
public function getData($key = '', $index = null)
{
if('' === $key)
{
$data = $this->_data;
foreach($data as $key => $value)
{
if(is_scalar($value))
{
$data[$key] = base64_decode($value);
}
}
}
else
{
$data = parent::getData($key, $value);
if(is_scalar($data))
{
$data = base64_decode($data);
}
}
return $data;
}
It would be nice if a similar encoding mechanism was part of core code.
I use Bootstrap and I would like to save the current state of collapse (open or close) in a session variables PHP (not in a cookie).
Could you give me :
- an example code to save the current state in a session variable PHP.
- and an example code to open or not the collapse (depends on the state stored in the session variable) when the page loads.
Thank you very much
First of all, do you really need to store it into session? Does some PHP script work with that value?
Both cases:
You must store somewhere in JavaScript variable the state of collapsed items:
var collapsed = false; // the default value
$('.collapse').on('hide.bs.collapse', function () {
collapsed = true; // on hide, collapsed is true
})
$('.collapse').on('show.bs.collapse', function () {
collapsed = false; // on show, collapsed is false
})
Yes, i need to store it into session:
At each request, you must add the collapsed variable and pass it for example trhough GET method:
$('a').on('mousedown', function() {
var c = collapsed ? 1 : 0;
var href = $(this).attr('href');
if(href.indexOf('?') !== -1) {
$(this).attr('href', href + '&collapsed=' + c);
else {
$(this).attr('href', href + '?collapsed=' + c);
}
});
And somehow save it to session
$_SESSION['collapsed'] = $_GET['collapsed'];
No, i don't need to store into session:
Most modern browsers now have localStorage variable, which is something like session in JavaScript.
Save into variable (in event handlers for example):
if(typeof(Storage)!=="undefined")
{
window.localStorage.setItem('collapsed', collapsed); // saves with no expiration
code.sessionStorage.setItem('collapsed', collapsed); // saves until browser is closed
}
else
{
// Sorry! No Storage support..
}
Load in some startup script:
if(typeof(Storage)!=="undefined")
{
collapsed = window.localStorage.getItem('collapsed'); // again choose one
collapsed = code.sessionStorage.getItem('collapsed');
if(collapsed) {
$('.collapse').collapse('show');
} else {
$('.collapse').collapse('hide');
}
}
else
{
// Sorry! No Storage support..
}
There may be other solutions, but these are the only i can think about. :)
All codes require jQuery
I would do something like this on the PHP side of things. It allows for storing and retrieving the state of multiple ID:s. Session handling is not included; the functions assume there is an active session going. Also, the functions are static since there is no real need to instantiate a class. And it makes for simpler usage.
class Collapse
{
public static function set_state($id = null, $state = null)
{
if ($id === null || $state === null || !is_numeric($state)) {
return false;
} else {
$state = ($state == 0 ? 0 : 1);
$_SESSION['collapse_state'][$id] = $state;
}
}
public static function state($id = null)
{
if ($id === null) {
return false;
} else {
return $_SESSION['collapse_state'][$id];
}
}
}
// --- Sets the state for chosen ID.
Collapse::set_state('info', 0);
// --- Returns the state of the ID.
Collapse::state('info');
Use this class together with the JavaScript proposed by Tomáš Tomíík Blatný and you'll be able to save your states. I'd probably use POST instead of GET though, to make the URL:s look a bit nicer. This can be done by populating a hidden form field or by sending an AJAX request to a PHP-script that only handles the collapse states.
How can I implement a righ-click context-menu in JqGrid for PHP ?
I am trying this solution by Oleg, but it is not working.
I would like to get this:
grid.php snippet:
$rightclick = <<<RIGHTCLICK
function () {
$("tr.jqgrow", this).contextMenu('myMenu1', {
bindings: {
'edit': function (trigger) {
// trigger is the DOM element ("tr.jqgrow") which are triggered
grid.editGridRow(trigger.id, editSettings);
},
'add': function ( /*trigger*/ ) {
grid.editGridRow("new", addSettings);
},
'del': function (trigger) {
if ($('#del').hasClass('ui-state-disabled') === false) {
// disabled item can do be choosed
grid.delGridRow(trigger.id, delSettings);
}
}
},
onContextMenu: function (event /*, menu*/ ) {
var rowId = $(event.target).closest("tr.jqgrow").attr("id");
//grid.setSelection(rowId);
// disable menu for rows with even rowids
$('#del').attr("disabled", Number(rowId) % 2 === 0);
if (Number(rowId) % 2 === 0) {
$('#del').attr("disabled", "disabled").addClass('ui-state-disabled');
} else {
$('#del').removeAttr("disabled").removeClass('ui-state-disabled');
}
return true;
}
});
}
RIGHTCLICK;
$grid->setGridEvent('loadComplete ', $rightclick);
Is there any way to get a context menu in JqGrid for PHP ?
First of all your code have unneeded space: 'loadComplete ' instead of 'loadComplete'.
I can repeat one more time that I don't use PHP myself and don't use setGridEvent of JqGrid for PHP too. So I can only guess that $grid->setGridEvent probably don't forward this correctly. In the case you can use setGridParam to set callback dynamically (see the answer) or to use jqGridLoadComplete event instead of loadComplete callback (see the answer).