Drupal - Search box not working - custom theme template - search

I am using a customised version of search-theme-form.tpl
When I use the search box, I do get transferred to the search page. But the search does not actually take place. The search box on the search results page does work though. This is my search-them-form.tpl.php file (demo :
<input type="text" name="search_theme_form_keys" id="edit-search-theme-form-keys" value="Search" title="Enter the terms you wish to search for" class="logininput" height="24px" onblur="restoreSearch(this)" onfocus="clearInput(this)" />
<input type="submit" name="op" id="edit-submit" value="" class="form-submit" style="display: none;" />
<input type="hidden" name="form_token" id="edit-search-theme-form-form-token" value="<?php print drupal_get_token('search_theme_form'); ?>" />
<input type="hidden" name="form_id" id="edit-search-theme-form" value="search_theme_form" />
There is also a javascript file involved. I guess it's use is pretty clear from the code:
function trim(str) {
return str.replace(/^\s+|\s+$/g, '');
}
function clearInput(e) {
e.value=""; // clear default text when clicked
e.className="longininput_onfocus"; //change class
}
function restoreSearch(e) {
if (trim(e.value) == '') {
{
e.value="Search"; // reset default text onBlur
e.className="logininput"; //reset class
}
}
}
What can be the problem and how can I fix it?

Apparently, you cannot directly modify the HTML in search-theme-form.tpl.php since thats not the right way to do it. So my adding the class and onFocus and onBlur attributes was the problem.
The correct way to do it is to modify the themes template.php file. Basically we will be using form_alter() to modify the form elements. Since using the HTML way is wrong. Take a look at the code below (taken from : here )
<?php
/**
* Override or insert PHPTemplate variables into the search_theme_form template.
*
* #param $vars
* A sequential array of variables to pass to the theme template.
* #param $hook
* The name of the theme function being called (not used in this case.)
*/
function yourthemename_preprocess_search_theme_form(&$vars, $hook) {
// Note that in order to theme a search block you should rename this function
// to yourthemename_preprocess_search_block_form and use
// 'search_block_form' instead of 'search_theme_form' in the customizations
// bellow.
// Modify elements of the search form
$vars['form']['search_theme_form']['#title'] = t('');
// Set a default value for the search box
$vars['form']['search_theme_form']['#value'] = t('Search this Site');
// Add a custom class and placeholder text to the search box
$vars['form']['search_theme_form']['#attributes'] = array('class' => 'NormalTextBox txtSearch',
'onfocus' => "if (this.value == 'Search this Site') {this.value = '';}",
'onblur' => "if (this.value == '') {this.value = 'Search this Site';}");
// Change the text on the submit button
//$vars['form']['submit']['#value'] = t('Go');
// Rebuild the rendered version (search form only, rest remains unchanged)
unset($vars['form']['search_theme_form']['#printed']);
$vars['search']['search_theme_form'] = drupal_render($vars['form']['search_theme_form']);
$vars['form']['submit']['#type'] = 'image_button';
$vars['form']['submit']['#src'] = path_to_theme() . '/images/search.jpg';
// Rebuild the rendered version (submit button, rest remains unchanged)
unset($vars['form']['submit']['#printed']);
$vars['search']['submit'] = drupal_render($vars['form']['submit']);
// Collect all form elements to make it easier to print the whole form.
$vars['search_form'] = implode($vars['search']);
}
?>
In yourthemename_preprocess_search_theme_form - 'yourthemename' will obviously reflect the name of your custom theme. Basically the code is self-explanatory. what with the comments and all.
So, basically thats the way it works.

Related

Using livewire defer, if input value has text the value is sent when pagination link is clicked- how to stop this?

I'm using livewire with pagination. I set the input to defer so that the search is not carried out until the search button is clicked. However, I have also noticed that if I have any text in the search box that value is sent whenever a pagination button is clicked. I've tried setting the value to "" in jquery $(document).on("click", ".page-link", () => $( "#inlineFormInput" ).val("")); when a pagination buttton is click but that has not solved the problem. And actually clearing the value could cause other problems.
The desired result is that, if for some reason a user leaves text in the searchbox that value is not passed if the user changes their mind and just clicks a pagination link. The input value should only be passed when the search button is clicked. Any help would be greatly appreciated.
livewire component html:
<div id="searchBoxRow">
<input wire:model.defer="search" wire:keydown.enter="updateFaculty" id="inlineFormInput" class="form-control" val="" type="search" autocomplete="off" placeholder="Seach for Name or Country" aria-label="Search">
<button wire:click="updateFaculty" class="btn btn-primary" id="facultyCardsSearchButton" type="submit">
<i class="bi bi-search button-icon"></i>
<span class="button-text">Search</span>
</button>
</div>
livewire php file:
<?php
namespace App\Http\Livewire;
use App\Models\Tag;
use App\Models\Faculty;
use Livewire\Component;
use Livewire\WithPagination;
class FacultyData extends Component
{
use WithPagination;
protected $paginationTheme = 'bootstrap';
public $search = null;
public $tagId = null;
public function updateFaculty(){
$search = $this->search;
$tagId = $this->tagId;
$this->emit('closeAutocomplete');
}
public function updatingSearch()
{
$this->resetPage();
}
public function render()
{
$tags = Tag::all();
$allFaculty = Faculty::searchFilter([$this->search, $this->tagId])->with('country', 'tags')->paginate(10);
return view('livewire.faculty-data', [
'allFaculty' => $allFaculty,
'tags' => $tags
]);
}
}
Here is an idea. You can use the updatingPage() of the $page property hook. When performing the page switch clean the search property. But, somehow you need to check if this is a result of a searched data before or just the client has had his way...well, my idea is get a flagged property to tell livewire what to do. For example
public $searchFlag = false;
public function updateFaculty(){
if ($this->search) // only of search has any value
$this->searchFlag = true;
// do
}
public function updatingPage()
{
if (! $this->searchFlag) {
$this->reset(['search']);
}
if (! $this->search) {
$this->reset(['searchFlag']);
}
}

update customer attribute in frontend account profile form

I'm learning Shopware and I got to something I can't figure out how to solve.
I'm writing a test plugin that adds an attribute to the customer. I've added the correspondent field to the Registration form and it saves its value to the db automatically, like I read somewhere in the docs.
Now I wanted to let the attribute be editable in the account profile page, after the password field. I managed to put the input there, and even show the value from the db. But when I change the value and save, the value its not updated. I don't know if it is just a matter of getting the field name right, or do I need to override something else. Or is it just not possible? Any help on how to achieve this would be greatly appreciated.
Relevant code below:
plugin bootstrap
public function install(InstallContext $context)
{
$service = $this->container->get('shopware_attribute.crud_service');
$service->update('s_user_attributes', 'test_field', 'string');
$metaDataCache = Shopware()->Models()->getConfiguration()->getMetadataCacheImpl();
$metaDataCache->deleteAll();
Shopware()->Models()->generateAttributeModels(['s_user_attributes']);
return true;
}
register/personal_fieldset.tpl
{extends file="parent:frontend/register/personal_fieldset.tpl"}
{block name='frontend_register_personal_fieldset_password_description'}
{$smarty.block.parent}
<div class="register--test-field">
<input autocomplete="section-personal test-field"
name="register[personal][attribute][testField]"
type="text"
placeholder="Test Field"
id="testfield"
value="{$form_data.attribute.testField|escape}"
class="register--field{if $errorFlags.testField} has--error{/if}"
/>
</div>
{/block}
account/profile.tpl
{extends file="parent:frontend/account/profile.tpl"}
{block name='frontend_account_profile_profile_required_info'}
<div class="profile--test-field">
<input autocomplete="section-personal test-field"
name="profile[attribute][testfield]"
type="text"
placeholder="Test Field"
id="testfield"
value="{$sUserData.additional.user.test_field|escape}"
class="profile--field{if $errorFlags.testField} has--error{/if}"
/>
</div>
{$smarty.block.parent}
{/block}
The form type that it's used on registration isn't the same you have on profile.
If you check \Shopware\Bundle\AccountBundle\Form\Account\PersonalFormType::buildForm, you can see
$builder->add('attribute', AttributeFormType::class, [
'data_class' => CustomerAttribute::class
]);
That means the attributes are included on form and they will be persisted. That's why you can save the value on registration form.
On profile you have \Shopware\Bundle\AccountBundle\Form\Account\ProfileUpdateFormType. And here the attribute isn't added to form builder.
How to extend the ProfileUpdateFormType?
Subscribe Shopware_Form_Builder on Bootstrap (or on a specific Subscriber class)
$this->subscribeEvent('Shopware_Form_Builder', 'onFormBuild');
Create the method onFormBuild to add your logic
public function onFormBuild(\Enlight_Event_EventArgs $event) {
if ($event->getReference() !== \Shopware\Bundle\AccountBundle\Form\Account\ProfileUpdateFormType::class) {
return;
}
$builder = $event->getBuilder();
$builder->add('attribute', AttributeFormType::class, [
'data_class' => CustomerAttribute::class
]);
}
With this approach all attributes are available on your profile form.
Other possibility you have is using the 'additional' property instead of 'attribute' and then subscribe a controller event or hook a controller action to handle your custom data.

Best practice to add a Test-Button in a Orchard-AdminView

I'd like to add a "Test"-Button to the Create/Edit-AdminViews in my Orchard-Module.
The Button itself is rendered fine using an additional shape.
Question: how can I make the button's action point to a "Test"-Action which gets the current ViewModel, performs the "Test", displays an info and returns the user to the view (passing the ViewModel back in again).
At the Moment, it completely ignores it's surrounding Form.
Maybe there's already some working example and I simply couldn't find it?
Thanks for any help.
Sascha
PS: Code in Content.TestButton.cshtml
#using ( Html.BeginFormAntiForgeryPost(Url.Action("Test", new { controller = "DnsCheckAdmin" }), FormMethod.Post, new { #class = "col-md-5" }) )
{
<fieldset class="test-button">
<button type="submit" name="submit.Test" value="submit.Test">#T("Test settings")</button>
</fieldset>
}

how to add object to a list in a view?

I have a strongly typed view where I have a form. I display values of a Contact (object) in Textboxes. The contact has a list of functions. I have also a list of all the functions that exist in database. In the view I'm listing all the functions by displaying checkboxes (value : Id of the function, display : name of the function). Before that, I compare the list of the Contact's functions to all to functions and I checked those of the contact. Like that :
#foreach (extranetClient.Models.Classes.FonctionContact fonction in ViewBag.Fonctions)
{
string coche = "";
if ((#Model.ListeFonctions).Where(c => c.IdFonction == fonction.IdFonction).Count() > 0)
{
coche = "checked";
}
<input type="checkbox" #coche id="#fonction.IdFonction" />#fonction.LibelleFonction <br />
}
It looks like that:
But now, if the user checks a checkbox to add a function to the contact, I need to save it in the contact's list. I cannot find how to do that. Somebody has idea ?
First we need to modify your checkboxes so they will post properly. When a checkbox is checked it will be posted like this name=value. But we want all your checkboxes to be posted into a collection, so the name will follow this format function[x] where x is an index of the checkbox. The value then becomes the ID of the function.
#{
var i = 0;
}
#foreach (extranetClient.Models.Classes.FonctionContact fonction in ViewBag.Fonctions)
{
string coche = "";
if ((#Model.ListeFonctions).Any(c => c.IdFonction == fonction.IdFonction))
{
coche = "checked";
}
<input type="checkbox" #coche id="functions[#(i++)]" value="#fonction.IdFonction" />#fonction.LibelleFonction <br />
}
Now create an action method which can receive the checkboxes's data. Simply provide a parameter which can recieve an enumeration of int assuming your function IDs are ints.
public ActionResult UpdateFunctions(IEnumerable<int> functions)
{
// TODO: functions contains IDs of all checked boxes.
}
Hope this helps.

Utilizing Bootstrap's typeahead as a search function

I've got typeahead working just fine, but I am too inexperienced with the Javascript to understand how to turn the typed results into a link.
<input type="text"
class="span3"
data-provide="typeahead"
placeholder="City Search:"
data-items="6"
autocomplete="off"
data-source=["Neuchatel","Moutier"]">
So, I really just want to know how to turn the strings from data-source into links to other pages. Hopefully this is fairly simple.
thanks!
You can turn the strings into links easily..
<input type="text" data-provide="typeahead" data-source="["/foo.html","http://www.google.com","/about.html"]">
Are you also looking to take the link from the input and then navigate to the selected page?
EDIT: Navigate to item selected in typeahead..
In this case you'd define an object map that contain keys (label) and values (url) like..
var data = {
"login":"/login",
"home":"/",
"user":"/user",
"tags":"/tags",
"google":"http://google.com"
};
Then you'd initiate the typeahead. The source and updater functions would be defined to handle 1) creating the typeahead data source array from the map object, and 2) navigate to the appropriate url when an item is selected..
$('.typeahead').typeahead({
minLength:2,
updater: function (item) {
/* navigate to the selected item */
window.location.href = data[item];
},
source: function (typeahead, query) {
var links=[];
for (var name in data){
links.push(name);
}
return links;
}
});
Demo on Bootply

Resources