Hi, im trying to do a ajax live search. It work`s, but i want it to be fast. Currently i`m processing the html by php, but even if i change the processing to js and only get the data from php it only improves my search from 2.1 to 1.8 seconds (this is the request time, but it takes 4/5 seconds for the data to appear)
Heres my code:
$("#searchfield").change(function() {
term = $(this).val();
if (searchReq != false) {
searchReq.abort();
}
searchReq = $.get("/searchModal.php", {
term : term
}).done(function(data) {
$("#liveSearch").html(data);
});
});
EDIT:
php code:
search.php:
$files = filecontroller::search($term);
file controller:
public static function search($term, $by = false, $order = false) {
connection::connect();
$files = ($by && $order && validation::filesOrder($by, $order)) ? file::Search($term, $by, $order) : file::Search($term);
return $files;
}
File model:
public static function Search($term, $by = 'date', $order = 'DESC') {
$session_id = $_SESSION["user_id"];
$term = mysql_real_escape_string($term);
$query = mysql_query("SELECT * FROM files WHERE idUser = '$session_id' AND (name LIKE '%$term%' OR description LIKE '%$term%') ORDER BY $by $order");
$files = self::CreateFromDb($query);
return $files;
}
private static function CreateFromDb($query) {
GLOBAL $imgDir; // just get the img dir from a config file
GLOBAL $userDir; // same
$files = array();
while ($row = mysql_fetch_assoc($query)) {
$file = new File();
$file -> type = $row['type'];
$file -> idFile = $row['idFile'];
$file -> user = $row['idUser'];
$file -> gallery = $row['idGallery'];
$file -> name = htmlspecialchars($row['name']);
$file -> description = htmlspecialchars($row['description']);
$file -> date = $file -> timecheck($row['date']);
$file -> size['kb'] = $row['size'];
$file -> galleryName = Gallery::getName($file -> gallery);
$files[] = $file;
}
return $files;
}
Is there anyway to improve it? Im testing in local.
There are some issues with your code, but nothing obvious.
Some starting points:
The best way to find what's slow is probably to check profiling in PHP.
Another thing is that you're using LIKE "%x%" which will be slow if your user has lots of files (seems unlikely, but who knows). Check the MySQL slow query log.
You're also doing some disk access, but it shouldn't be this slow either - unless something strange is going on inside Gallery::getName or timecheck.
Note that the mysql extension has been deprecated. This has nothing to do with speed though, it's just outdated.
ANSWER
.change has a delay, for real time results its better to use .keyup. I cme up using a timeout to make the request only when user stop typing:
var searchTimeout;
var searchReq;
$("#searchfield").on('keyup', function() {
term = $(this).val();
if (searchTimeout) {
clearTimeout(searchTimeout);
}
if (searchReq) {
searchReq.abort();
}
searchTimeout = setTimeout(function(){
if (term.length > 2) {
searchController(term).then(function(data) {
$("#liveSearch").html(data);
});
}
else {
$("#liveSearch").html("");
}
},500);
});
function searchController(term) {
searchReq = $.ajax({
type : "GET",
url : "/searchModal.php",
data : {
term : term
},
async : true,
context : this,
beforeSend : function() {
},
complete : function() {
}
});
return searchReq;
}
Its still slow compared to facebook, and other big sites. I guess the only way to acess it fast would be with a great server or cached results (i tried to just echo an string without bd requests and its slow too).
Related
I just started using redis to cache data and run queries. I have two functions, one for fetching the data, and another one for filtering the cached data. This is how my function for fetching data looks :
if (Auth::user()->access_level == 'Admin' || Auth::user()->access_level == 'Donor') {
$clients_number = Cache::remember('all_clients_number', 21600, function () {
return ClientPerformance::whereNotNull('actual_clients')->get();
});
$all_clients_number = Cache::remember('all_clients_sum', 21600, function () use ($clients_number) {
return $clients_number->sum('actual_clients');
});
} else if(Auth::user()->access_level == 'Partner') {
$clients_number = Cache::remember('all_partner_clients_number', 21600, function () {
return ClientPerformance::whereNotNull('actual_clients')
->where('partner_id', Auth::user()->partner_id)
->get();
});
$all_clients_number = Cache::remember('all_partner_clients_sum', 21600, function () use ($clients_number) {
return $clients_number->sum('actual_clients');
});
}
I have confirmed that my redis service is running and i changed the maximum memory limit in my php.ini file to be 4096.
This is how my function to filter the data looks like :
$selected_counties = $request->counties;
if (Auth::user()->access_level == 'Admin' || Auth::user()->access_level == 'Donor') {
$all_clients_number = Cache::remember('all_clients_number', 21600, function () {
return ClientPerformance::whereNotNull('actual_clients');
});
} else if(Auth::user()->access_level == 'Partner') {
$all_clients_number = Cache::remember('all_partner_clients_number', 21600, function () {
return ClientPerformance::whereNotNull('actual_clients');
});
}
if (!empty($selected_counties)) {
$all_clients_number = $all_clients_number->where('county_id', $selected_counties);
}
$data["all_clients_number"] = $all_clients_number->sum('actual_clients');
Is it good practice to access the cached data from another function like this Cache::remember(key) and what could be the reason why i cant write anything to redis despite the fact that the data im caching is not that heavy.
Any advise or links to places i can read how to effectively access cached redit data will be appreciated. Thanks.
There are some workaround which can solve the issue this:
update the redis server to version 5 or 6
CONFIG SET maxmemory 0
I was wondering if there was a way that I could list all the views load / included / extended in a response?
I know of laravel-debugbar, but I'd like to do it from within my code for Unit Testing purposes.
Just to clarify: I'm not looking to list all of the views in my resources folder. I'd like to get a list of all views used in the current response/request.
Thanks!
I have done something similar for myself. It's not perfect. Create the following route with function:
Route::get('list-views', function(){
$full_path = 'FULL-PATH-TO-YOUR-LARAVEL-VIEWS-FOLDER'; //LIKE /home/account/www/resources/views/
if(!is_dir($full_path))
return 'Views directory not found';
$files = scandir($full_path);
unset($files[0]);
unset($files[1]);
if(($key = array_search('emails', $files)) !== false) {
unset($files[$key]);
}
foreach($files AS $file){
$link = str_replace('.blade.php','',$file);
echo ''.$link.''.'<br>';
}
});
What this function does is checks if the views path exists which you define in the variable $full_path, scans that directory for view files. Now, list-views will list all available views.
laravel debugbar does that, but in my case i cant find a way to list all the views under the same url in one go, so if anyone nows how i would deeply appreciate it.
// EventServiceProvider#boot()
app('events')->listen('composing:*', function ($view, $data = []) {
$url = url()->current();
$view = $data[0];
$name = $view->getName();
$path = ltrim(str_replace(base_path(), '', realpath($view->getPath())), '/');
logger([$url=>$path]);
});
another way could be but this will only display the main view "not the nested or parent"
// EventServiceProvider#boot()
use Illuminate\Foundation\Http\Events\RequestHandled;
app('events')->listen(RequestHandled::class, function ($event) {
$request = $event->request;
$response = $event->response;
$check = !$request->ajax() &&
!$request->pjax() &&
$request->isMethodCacheable() &&
$response->isSuccessful();
if ($check) {
$view = $response->original;
$path = ltrim(str_replace(base_path(), '', realpath($view->getPath())), '/');
logger([$request->url(), $path]);
}
});
you can also get the view from a middleware but this will only display the main view same as b4
public function handle($request, Closure $next)
{
$response = $next($request);
$check = !$request->ajax() &&
!$request->pjax() &&
$request->isMethodCacheable() &&
$response->isSuccessful();
if ($check) {
$view = $response->original;
$path = ltrim(str_replace(base_path(), '', realpath($view->getPath())), '/');
logger([$request->url(), $path]);
}
return $response;
}
I'm trying to make a user friendly way of testing via lime in symfony 1. I want to load a specific sql dump for each test I write (if required). The problem I face is that I don't know how to make dump loading independent of database type. Currently I'm using the shell exec() command. Here is the code :
public function loadSql()
{
$this->diag("Loading dump...");
if ($this->_sql_is_set)
{
if (file_exists($this->_getSqlPath()))
{
$this->_emptyDataBase();
$options = $this->_connection_manager->connection()->getOptions();
$dsn_parts = $this->_connection_manager->parsePdoDsn($options['dsn']);
exec("mysql -u{$options['username']} -p{$options['password']} {$dsn_parts['dbname']} < {$this->_getSqlPath()}");
return $this;
}
else
{
$this->error("Nothing to load : sql file was not found in ".$this->_getDataDir());
exit;
}
}
else
{
$this->error("Nothing to load : sql dump was not set");
exit;
}
}
$this->_connection_manager is an instance of Doctrine_Manager. Any help will with that?
Try with something like that:
public function loadSqlFiles(sfEvent $event)
{
$task = $event->getSubject();
$taskName = $task->getName();
if ($taskName == 'insert-sql') {
$conn = Doctrine_Manager::connection();
$filesPath = sfConfig::get('sf_data_dir') . '/sql/full-data';
// get all files
$files = sfFinder::type('file')->sort_by_name()->name('*.sql')->in($filesPath);
foreach ($files as $file) {
$task->logSection('custom-sql', sprintf('Inserting custom sql file (%s)', $file));
$res = $conn->getDbh()->exec(file_get_contents($file));
}
}
}
All,
Background of how problem was detected
My question concerns the performance of a web app, mainly the index page. I noticed the problem when I was giving a demonstration at a local branch of my company that has slow internet (I don't know the exact speeds, or ping rate) judged by the fact that Google took about 10 seconds to load. My index page took ~10-20 times longer to load. I was under the assumption that my app did most of the work on the server side (as php is making all of the database queries...). But this led me to look at the network tool of Chrome and see the latency times of these 4 divs being loaded by ajax (I'll elaborate in a bit). Interestingly, the scripts being called appear to run sequentially, but not necessarily in the order I invoked the ajax calls (sometimes they do, other times they don't).
What are these divs / ajax requests?
Here is a code snippets of a request:
Yii::app()->clientScript->registerScript('leftDiv', '
$( "#left_dash" ).load(
"'.$this->createUrl("/site/page?view=leftDashLoad") .'",
function(){
$("#left_dash p a").click(function() {
$(this).parent().parent().find("div.scroll100").slideUp();
$(this).parent().next().stop(false, false).slideDown();
});
$("p:first-child").next().slideDown();
}
);
' );
Here is the page requested:
$this->widget('widgets.ScrollList',array(
'condition'=>
function($muddJob,$scrollList)
{
$job = $muddJob->Job;; //returns a job or empty array
if(!empty($job) )
{
if( $muddJob->uploadArtwork == null && $muddJob->uploadData == null ) {
array_push($scrollList->_models,$job);
$scrollList->columnValues = array($muddJob->jobDescription,$muddJob->dropDate1);
return true;
}
}
return false;
},
'columns' => array('col1'=>"MuddJob#",'col2'=>"Desc",'col3'=>"Dealer Name"),
'name'=> "Print New Ticket",
'muddJobs' => $currentExchanges->getCurrentMuddExchanges(),
)
);
Imagine that page (the page that ajax has called) having 6 similar declarations that create widgets. The goal is to return html to put back in place of a loading gif on the index page.
Here is the scroll widget:
<?php
Yii::import('widgets.ScrollListBase');
include_once Yii::app()->extensionPath . "/BusinessDay.php";
class ScrollList extends ScrollListBase
{
private $_content;
public $columns = array();
public $columnValues;
private $_listInfo;
public $name;
public $_models = array();
public $condition;
public $muddJobs; //object to pass
public $jobsMailingTodayArray = array();
public function init()
{
//$this->init();
$this->_listInfo = $this->generateListInfo($this->columns);
//$muddJobs = $this->getCurrentMuddExchanges();
$listInfo = $this->newScrollList($this->muddJobs);
$contents = $this->createContent($listInfo,$this->name);
$this->_content = $contents[0];
// $this->_fullTableContent = $contents[1];
//$this->_listInfo = $contents[2];
}
public function run()
{
//if($this->data['isVisible'])
echo $this->_content;
Yii::app()->session["exploded_content_{$this->name}"] = $this->_models;
}
private function newScrollList($muddJobs)
{
$listInfo = $this->_listInfo;
$tempCount = 0;
foreach($muddJobs as $muddJob)
{
$condition = $this->condition;
if($condition($muddJob,$this) && empty($this->jobsMailingTodayArray) ) //if no job exists for the muddExchange...
{
$tempArray = $this->createWidgetLinks($tempCount,$listInfo,$muddJob,$this->columnValues);
$listInfo = $tempArray[0];
$tempCount = $tempArray[1];
}
elseif ( !empty($this->jobsMailingTodayArray ) )
{
foreach ($this->jobsMailingTodayArray as $jobMailingToday) //change to for loop over the length of the jobsMailingToday
{
$tempArray = $this->createWidgetLinks($tempCount,$listInfo,$muddJob,$this->columnValues);
$listInfo = $tempArray[0];
$tempCount = $tempArray[1];
}
$this->jobsMailingTodayArray = array();
}
}
return array($listInfo,$tempCount);
}
}
?>
Here is it's parent:
<?php
class ScrollListBase extends CWidget
{
private $content = "<p>";
private $divDeclaration = "<div class='scroll100'>\n<table class='quickInfoTable'>\n<thead>\n";
private $headTag = "<th>";
private $headTagClose = "</th>\n";
private $theadTagClose = "</thead>\n";
private $bodyTag = "<tbody>\n";
private $listInfo = "<div class='scroll100'>\n<table class='quickInfoTable'>\n<thead>\n<th>Job#</th>\n<th>Package#</th>\n<th>Entry Date</th>\n</thead>\n<tbody>\n";
/**
* Initializes the widget.
*/
public function createContent($listInfo,$name)
{
$largeHref = Yii::app()->request->baseUrl . '/index.php/site/fullTableView';
$this->content .= "<span class='badge' >{$listInfo[1]} </span> <a href='#'>{$name} </a> <a href='$largeHref/Name/{$name}'> <small>(view larger)</small> </a> </p>";
if( $listInfo[1] > 0 )
{
// $this->fullTable .= substr($listInfo[0],22);
// $this->fullTableContent= $this->fullContent .= $this->fullTable . "</tbody>\n</table>\n</div>";
$this->content .= $listInfo[0] . "</tbody>\n</table>\n</div>";
}
return array($this->content);
}
//Helper Methods
/**
*
* #param type $attributeArray. send an accociative array
* #return type = either a job or an empty array
*/
protected function getJobByAttributes($attributeArray)
{
return Jobs::model()->with('MuddExchange')->findByAttributes($attributeArray);
}
protected function createWidgetLinks($tempCount,$listInfo,$muddJob,$columnValues,$url="/MuddExchange/")
{
$tempCount++;
$viewIndex = $muddJob->exchange_id;
$model = $muddJob;
$job = $muddJob->Job;
if ( isset($job ))
{
$model = $job;
$url = "/Jobs/";
$viewIndex = $model->job_id;
}
$link = CHtml::link("$model->jobNumber",array("{$url}{$viewIndex}"));
$listInfo .= "<tr>\n<td>$link</td>\n";
foreach ($columnValues as $columnValue)
{
$listInfo .= "<td>{$columnValue}</td>\n";
}
$listInfo .= "</tr>";
return array($listInfo,$tempCount);
}
protected function getListInfo()
{
return $this->listInfo;
}
/**
* Takes an array of strings to generate the column names for a particular list.
* #param array $heads
* #return string
*
*/
protected function generateListInfo($heads)
{
//<th>Job#</th>\n<th>Package#</th>\n<th>Entry Date</th>\n</thead>\n<tbody>\n";
$htmlScrollStart = $this->divDeclaration;
foreach ($heads as $tableColumn => $name)
{
$htmlScrollStart .= $this->headTag . $name . $this->headTagClose;
}
$htmlScrollStart .= $this->theadTagClose . $this->bodyTag;
return $htmlScrollStart;
}
public function calculateDueDate($jobsMailDate,$job)
{
$package = PackageSchedule::model()->findByAttributes(array('package_id'=>$job->packageID));
$projectedDays = $package->projected_days_before_mail_date;
$dropDate1 = $jobsMailDate->projected_mail_date;
$dropDate = wrapBusinessDay($dropDate1); //use this for actual command...
$toSec = 24*60*60;
$dayInt =0;
$secDropDate = strtotime($dropDate1);
do{
$dayInt +=1;
$daysInSec = ($dayInt) * $toSec ;
$secGuessDueDate = $secDropDate - $daysInSec;
$dueDate = date('Y-m-d',$secGuessDueDate);
$difference = $dropDate->difference($dueDate);
}while( $difference != $projectedDays);
return $dueDate;
}
}
?>
Why I think this behavior is odd
The whole slow internet thing is a beast in and of itself, but I don't think that is in the scope of StackOverflow. I'm more concerned about the loading of these divs. The div that loads last, i.e., takes on average 1.5 to 2 seconds, is an ajax request to a page that creates a single widget. The logic behind it is here:
<?php
include_once Yii::app()->extensionPath . "/CurrentExchanges.php";
$currentExchanges = Yii::app()->session['currentExchanges'];
$this->layout = 'barebones';
$this->widget('widgets.ScrollList',array(
'condition'=>
function($muddJob,$scrollList)
{
if ($muddJob->dropDate1 != null && $muddJob->dropDate1 != '0000-00-00')
{
$job = $muddJob->Job;;
if(!empty($job) && $job->packageID != null) //if job exists for the muddExchange and has a package
{
if($job->uploadArtwork == null )
{
$jobsMailDate = JobsMailDate::model()->findByAttributes(array("job_id"=>$job->job_id,'sequence_num'=>1));
if(!empty($jobsMailDate))
{
$calculatedDueDate = $scrollList->calculateDueDate($jobsMailDate,$job);
if (strtotime($calculatedDueDate) <= strtotime(date("Y-m-d")) )
{
array_push($scrollList->_models , $job);
$scrollList->columnValues = array($muddJob->jobDescription,$muddJob->dropDate1,$jobsMailDate->projected_mail_date);
return true;
}
}
}
}
}
return false;
},
'columns' => array('col1'=>"MuddJob#",'col2'=>"Desc",'col3'=>"Drop Date", 'col4' =>'Projected Drop Date'),
'name'=> "Artwork Due Today",
'muddJobs' => $currentExchanges->getCurrentMuddExchanges(),
)
);
?>
The calculateduedate method makes 2 additional calls to the server.
What I'm failing to understand is why the left div (with the most proccessing to do) is usually the first to return and the artLoad is usually the last to load (by a substantial difference). Here are some times returned by chromes network tool:
leftDashLoad: 475ms
rightDashLoad: 593ms
dataLoad: 825ms
artLoad: 1.41s
dataLoad: 453ms
rightDashLoad: 660ms
leftDashLoad: 919ms
artLoad: 1.51s
rightDashLoad: 559ms
leftDashLoad: 1.17s
dataLoad: 1.65s
artLoad: 2.01s
I just can't fathom why the left/right dashloads return so much faster than the artLoad. The code for artLoad and dataLoad are nearly identical save the actual comparison (the one if statement). If this were truly asynchronous, I'd expect the order to be art/dataLoad, rightDashLoad and leftDashLoad based purely on the amounts of computation done in each page. Perhaps the server isn't multithreading, or there is some weird configuration, but if that were the case, I don't see why the effects of the loading would be hit so hard by slow internet.
If I have overlooked something obvious or failed to use google appropriately, I do apologize. Thanks for any help you can offer!
Language/other tech info
The app was developed using the Yii framework. PHP 5.3. Apache Server. INNODB Tables. Server is hosted in dreamhost.
Update
I've changed the view page so that the ajax calls are now calling a controller action. It seems to have made the loading times more similar (asynchronous?) on my local dev environment, but really slowed it down on the QA environment (hosted on dreamhost...). Here is screen shot of the local network tools info:
dev environment
and the qa site (note, that the databases have about the same amounts of data...)
qa environment
Thoughts? It seems to me that my original problem may be solved, as the return times (on my local dev) look more like I expect them to.
Also, my own ignorance as to how NetBeans debugs was playing a part in this synchronous loading thing as xdebug is using a session. I believe this was forcing the ajax calls to wait their turn.
Thanks to #Rowan for helping me diagnose this strange behavior. PHP was trying to request a session before the session was closed in hopes to prevent a race hazard. There were session requests in my code, and there was a session started by my IDE (NetBeans). Removing all references to sessions in the ajax called pages and having ajax call actions that use renderPartial() proved to return the expected behavior (and much better code IMO). Let me know how to properly thank users in terms of StackOverflow (can I up comments, or what is there available? ). Thank you all!
(Original Questions) I am using jquery ui's selectable script to control specific active keywords in my webapp. View here: www.rickymason.net/letschat/main/home for reference
I have very little experience with javascript and I'm trying to figure out how to launch a function I have in my main model.
Updated function based on answers:
I have updated my code to support the new JSON/AJAX format. This required me to create an active/inactive session filter so that the user can add filters normally, and always use AJAX to update the thread list. This just made more sense to me.
Here is the code I have currently, which still is not working. I am attempting to make it so when the user clicks on a selectable category (through Jquery UI), the divID associated with the selection is passed through AJAX and returns a threadlist array that updates the div id ="board".
Here is my current Controller set up:
public function home($page = 'home')
{
$data['user_id'] = $this->tank_auth->get_user_id();
$data['username'] = $this->tank_auth->get_username();
$data['threads'] = $this->thread_model->session_load();
$data['title'] = ucfirst($page); // Capitalize the first letter
$data['page'] = $page;
$this->load->view('templates/head', $data);
$this->load->view('templates/nav', $data);
$this->load->view('main/newthread', $data);
$this->load->view('main/addfilter', $data);
$this->load->view('main/checkbox', $data);
$this->load->view('main/displayfilter',$data);
$this->load->view('main/board', $data);
$this->load->view('templates/footer');
}
public function updatefilters($filters)
{
$filterarray = split("|", $filters);
$this->thread_model->create_session_filter($filterarray);
$threadarray = $this->thread_model->get_threads();
$data['json'] = '{"content":' + $threadarray + '}';
$this->load->view('json_view', $data); // See step 4!!!
}
Here is my current model code:
public function get_threads()
{
$filter = $this->session->userdata('filter');
$num_tags = count($filter);
if ($num_tags > 0 && $num_tags <= 8) {
$sql_select = "SELECT DISTINCT t.* ";
$sql_from = " FROM ";
$sql_where = " WHERE ";
$sql_joins = "";
$sql_order = "ORDER BY t.timestamp DESC";
for ($i=0;$i<$num_tags;++$i) {
if ($i==0) {
$sql_from .= " filter AS f ";
$sql_where .= " f.tag LIKE '%" . $filter[0] . "%'";
$sql_joins .= " INNER JOIN filter_thread AS ft ON ft.filter_id = f.filter_id
INNER JOIN thread AS t ON ft.thread_id = t.thread_id";
}
else {
$sql_where .= " OR f.tag LIKE '%" . $filter[$i] . "%'";
}
}
} else {
break;
}
$sql = $sql_select . $sql_from . $sql_joins . $sql_where . $sql_order;
$query = $this->db->query($sql);
$thread = $query->result_array();
return json_encode($thread); //I am aware this is not correct
}
public function create_session_filter($filterstring)
{
$filterarray[] = $filterstring;
$filter['filter'] = $filterarray;
if ($this->session->userdata('filter') == TRUE) {
$sessionfilter = $this->session->userdata('filter');
$new = array_merge($sessionfilter, $filter['filter']);
$this->session->unset_userdata('filter');
$filter['filter'] = $new;
$this->session->set_userdata($filter);
} else {
if (!$filterstring) {} else {
$this->session->set_userdata($filter);
}
}
}
public function create_session_inactive_filter($filterstring)
{
$filterarray[] = $filterstring;
$filter['inactivefilter'] = $filterarray;
if ($this->session->userdata('inactivefilter') == TRUE) {
$sessionfilter = $this->session->userdata('inactivefilter');
$new = array_merge($sessionfilter, $filter['inactivefilter']);
$this->session->unset_userdata('inactivefilter');
$filter['inactivefilter'] = $new;
$this->session->set_userdata($filter);
} else {
if (!$filterstring) {} else {
$this->session->set_userdata($filter);
}
}
}
And here is my current view code:
application/main/json_view.php
<?php
header("Content-Type: application/json");
echo $json;
?>
aplication/main/bdisplayfilter.php
<script>
$(function() {
$( "#selectable" ).selectable({
selected: updateFilters,
unselected: updateFilters
});
function updateFilters(ev, ui){
alert ("hello");
// get the selected filters
var $selected = $('#selectable').children('.ui-selected');
// create a string that has each filter separated by a pipe ("|")
var filters = $selected.map(function(){return this.id;}).get().join("|");
$.ajax({
url: '/main/updateFilters', //see step 2
data: { filters: filters },
success: function(data){
// data is whatever json you decide to return from the server.
// An easy way to do things is have data look like this:
// { content: "<div>All my new threads that I want to show up</div>" }
// then, you can replace some element on the page with the new content
// For example, say your container has an id of threadContainer:
$('#select').replaceWith(data.content);
}
}); }
});
</script>
<ol id="selectable">
<li class="ui-state-default" id="everything">Everything!</li>
<li class="ui-state-default" id="entertainment">Entertainment</li>
<li class="ui-state-default" id="sci/tech">Sci/Tech</li>
<li class="ui-state-default" id="news">News</li>
<?php
if ($this->session->userdata('inactivefilter') == true) {
$inactivefilter = $this->session->userdata('inactivefilter');
foreach ($inactivefilter as $new)
{
echo "<li class='ui-state-default' id='custom'>$new</li>";
}
}
?>
</ol>
<?php
if ($this->session->userdata('inactivefilter') == true) {
echo "<form action='".base_url()."main/clear_filter'><input type='submit' value=clear></form>";
} ?>
EDIT: I've updated the url and data parts of the ajax call and added an additional step to enable query string parameters.
1) Make the AJAX call
You will want to make the same call for selected and unselected, since you can have multiple filters and you need things to update accordingly on both events. So, I'll define a common function that both events can call.
$(function() {
$( "#selectable" ).selectable({
selected: updateFilters,
unselected: updateFilters
});
function updatefilters(ev, ui){
// get the selected filters
var $selected = $('#selectable').children('.ui-selected');
// create a string that has each filter separated by a pipe ("|")
var filters = $selected.map(function(){return this.id;}).get().join("|");
$.ajax({
url: '/index.php',
data: { c: main, m: updateFilters, filters: filters },
success: function(data){
// data is whatever json you decide to return from the server.
// An easy way to do things is have data look like this:
// { content: "<div>All my new threads that I want to show up</div>" }
// then, you can replace some element on the page with the new content
// For example, say your container has an id of threadContainer:
$('#threadContainer').replaceWith(data.content);
}
});
}
});
2) Enable query string parameters in application/config.php
The section called Enabling Query Strings at the bottom of this article explains how to do that:
http://codeigniter.com/user_guide/general/urls.html
3) Create an action that will receive the filters
Note that I'm using a controller called Page (which would live in /application/controllers/page.php). This action (updateFilters) could live in any controller you want.
class Page extends CI_Controller {
function __construct()
{
parent::__construct();
}
function index()
{
}
function updateFilters($filters)
{
$filterarray = split("|", $filters);
create_session_filter($filterarray);
$articlesHTML = getThreadList($filterarray); // See step 4!!!
$data['json'] = '{"content":' + $articlesHTML + '}';
$this->load->view('json_view', $data); // See step 5!!!
}
/* I've updated this slightly to accept an array */
public function create_session_filter($filterarray)
{
$filter['filter'] = $filterarray;
//... the rest of your stuff you already had
}
}
4) Implement getThreadList method
I don't think you mentioned if you already had something set up for this. This would basically take an array of filters and then render a thread list based off that.
5) Create json_view (if not already there)
This will set the content type so that the browser knows the content is json.
In /application/views/json_view.php:
<?php
header("Content-Type: application/json");
echo $json;
?>