ExtJS 4 - How to load grid store with its params carrying latest values from a form? - forms

I have a window with a search form at the top and grid at the bottom.
User can enter values in the search form and click button - Get Records.
At the click of this button, I load the store of the grid by passing the values in form fields as parameters in following way:
store.load({
params:{
key1:Ext.getCmp('field1').getValue();
}
});
I tried giving parameters in the store proxy itself, but it unfortunately always takes up initial values (values when the form is rendered) and not the latest one entered by the users in the form fields. Following is the method I used for assigning values to params while creating the store:
extraParams:{
key1:Ext.getCmp('field1').getValue();
}
I wanted to seek guidance at two things:
a. While defining a store, can I ensure that store takes latest/current values from the form fields before querying server, so that I don't have to provide these values while calling load function?
This becomes more necessary as I have a paging toolbar at the bottom which carries a refresh button (along with next, last, previous, first icons for navigation).
Now, whenever user clicks at refresh (or any navigation icon), the store gets loaded without the query parameters.
Thus the second thing is:
b. If the answer of 'a' is that - Pass the latest values to parameters manually when calling load function - then how can I write the handler for 'refresh' button and navigation icons (that is, next, last, previous and first) in the paging toolbar, so that I can pass the latest form values to load function.
Thanks for any help in advance.
PS: I am using ExtJS 4.

yourStore.on('beforeload',function(store, operation,eOpts){
operation.params={
status:cmbStatus.getValue(),
value:txtBuscarPor.getValue(),
empresa:'saasd',
app:'dsads'
};
},this);

Related to your question (b) (and because you especially asked for this in the comments section):
I see only one standard way to hook into the PagingToolbar button handlers which is very limited.
Ext.toolbar.Paging fires a 'beforechange' event before it actually changes the current page. See API docs. A listener that returns false will stop the page change.
All other methods require extending Ext classes which wouldn't be a problem if the ComboBox would make it easier to use your own implementation of BoundList (which is the class that renders the dropdown) or pass through config parameters to BoundList resp. the paging toolbar.
I tried to bring this lack of flexibility up on the Ext message board once but was pretty much ignored.

A possible solution for this is to use 'beforeload' event of the store and provide the list of parameters in it. This way, whenever the store is loaded, then its beforeload event is fired and the values picked up are always the latest. Hope this helps someone looking for something similar.

Related

Keep two react-bootstrap-typeahead inputs in sync

So I have an application with a dashboard and a main page that has a header. Both of them have a react-bootstrap-typeahead input to perform the same action - a search to open something on a map.
What I would like to achieve is:
when the user search something on the dashboard, the main page opens with the search result and on the header, the search input there shows what was searched on the other component.
on the other hand, when the user search something on the search input on the main page header, and then goes back to the dashboard, the dashboard search input should be prefilled with the value previously searched on the main page.
What I have tried so far:
So when the user picks a search item result, that string is saved on the application state using redux. I also clear it manually when the user clicks on the clear search button. The RBT component is defined to use this variable, as in:
<AsyncTypeahead defaultInputValue={props.currentSearchValue} ... />
This seams to work on the first time, i.e. when the user has not interacted with the other input yet. For example, with the application on a fresh state (just loaded) if on the dashboard I pick a search item, when going to the main page because that search input has not been touched yet. Then, when I pick a search item on the main page and go back to the dashboard, I wouldn't see it because setting defaultInputValue is not enough, as that input is not in its default state anymore.
Any tips? I have been running in circles so far. Tried the key/setKey workaround as described in another answer, but that wasn't enough to cover the case described on the previous paragraph. I also tried comparing the input value to the recorded value, but naturally when starting to typing with the input field the values would be different and therefore I cannot trigger a component reload based on that.
Thanks in advance.
Unless I'm missing something about your use case, the selected prop should do what you need. You can save the selected item(s) in your redux store and populate the typeahead with the value on the given page.
// Get the initial value from the store. This should be an array.
const typeaheadSelections = useSelector(...);
<Typeahead
...
onChange={(selected) => {
// Update the value in the store when the selection changes.
dispatch({
type: 'set-typeahead',
value: selected,
});
}}
selected={typeaheadSelections}
/>

How to make a custom ListView page in SuiteCRM

I need to make a page in SuiteCRM (v7.9 -- based loosely on Sugar 6.5 CE) that has a list of objects (of a custom module), with checkboxes in front of each one. So far, so good: that's a standard ListView.
The catch is that only some records should be in the list (filtering on whether there is an associated row in a related custom module/object).
This page needs to be distinct from the "regular" list for this module, which should indeed list all records.
It seems to me it makes sense to use a custom "action" to access this page view, and I can get my custom action code to fire with the right URL.
But I don't see how to hook in the filtering. At first, it looked like the process_record logic hook might be helpful here, but it just gives the bean for every record to be displayed. Unless there's a flag "display this record" that I'm not seeing, that's not so helpful.
Ideally, of course, I'd like to be able to inject a different WHERE clause in my custom controller action before calling
parent::action_listview();
to display the page, but I'm not seeing doc to indicate how that might work. I would include source code, but so far, the line above is everything (but boilerplate) that's in the controller.php file.
Create a copy of listview in custom folder and then override the listview's listViewProcess() method and insert your query there:
function listViewProcess() // generating listview
{
$this->processSearchForm();
if($this->where==''){
$this->where.="leads.status='Converted'";
}
$this->lv->searchColumns = $this->searchForm->searchColumns;
if(!$this->headers)
return;
$this->lv->setup($this->seed, 'custom/modules/Leads/ListView/ListViewGeneric.tpl', $this->where, $this->params);
echo $this->lv->display();
}
More info: http://wiki-crm-forum.com/forum/viewtopic.php?f=2&t=9420&p=32674&hilit=listViewProcess&sid=21907ecd28734a726f61f7017a7e9a24#p32674
Another tested working example can be found here:
How to hard code the where condition in list view ,basic search,advance search in sugar CE
P.S: I'm not so sure about "v7.9 -- based loosely on Sugar 6.5 CE" I'd say it's 95% identical apart from API stuff
for custom modules in SuiteCRM.
You may change in function create_new_list_query.

GTM Reduce number of tags

GTM up and running, main UA tag in place along with a ClickListener tag.
To reduce the number of macros, i use dataLayer variable Macros for event category, action, label, value & interaction, so they can be used for many rules and tags.
So i want to collect data from one link/button (Add to Fav), i add a rule to listen for the click using {{event}} equals gtm.click and {{Event Label}} equals Add_to_Fav (the label i push to the DL via onclick.
All good so far, but i need to create another UA tag (Track Type - event) that fires on the rule made previously. And this is my question, using this method seems to create many tags. If i have another 20 links that i want to collect data from, do i need to keep creating tags like this. Surely, this will affect page load speed with many tags firing on all pages.
Hope thats all clear.
If you need to retrieve the link text to use it as an event label you do not need many many event tracking tags, that would be horribly verbose. Instead you can use a custom javascript macro - the cool thing about them being that you can use existing macros inside your custom function.
If you create a click listener or link click listener this will create a few macros - one of them is {{element}}, which is the DOM element that received a click.
Now you create a macro of the type "custom java script", which must contain an anonymous function with a return value.
The barebones version of a function that retrieves the text of a clicked link would be
function() {
var el = {{element}};
return el.innerText;
}
(actually you do not need the variable assigment, you could use {{element}}.innerText directly).
You name the macro e.g. Linktext and use the macro {{Linktext}} in your single event tracking tag where it will dynamically be set to the value of the text of the clicked link (although you might want to check cross browser support for innerText, or maybe use innerHTML instead which serves in you use case probably the same purpose).

symfony form - delete embedded form object

I have a two Symfony forms:
ShoppingListForm
ShoppingListItemForm
I'm embedding the ShoppingListItemForm inside the ShoppingListForm many times. i.e. A shopping list contains many items.
So the ShoppingListItemForm consists of two widgets:
item_id (checkbox)
shopping_list_id (hidden - foreign key)
What I would like to do is delete the corresponding ShoppingListItem object if the object exists and the checkbox is left unchecked.
I'm not sure how this delete would occur? Would I use a post validator to see which fields have/haven't been checked? I'm a bit lost on this one.
I'd do this by over-riding the ShoppingListForm's updateObject method and putting your custom delete() etc calls in there (be sure to call parent::updateObject() within it).
Depending how you implement it, you may also need to remove the embedded forms and their values to ensure saving still works correctly for the remaining objects. Try without, but if you do, you need to clear the following:
unset($taintedValues['ShoppingListItem'][$key]);
unset($this->embeddedForms['ShoppingListItem'][$key]);
unset($this->validatorSchema['ShoppingListItem'][$key]);
unset($taintedFiles['ShoppingListItem'][$key]);
If you want to see a custom updateObject method to get an idea how to interact with values etc:
http://www.symfony-project.org/forms/1_2/en/11-Doctrine-Integration#chapter_11_sub_customizing_the_updateobject_method
personnally, I would loop through the existing list items to see whether the corresponding checkboxes are checked in the action, and call the delete() method on the items for which it is not the case. I don't think it is the purpose of a post validator, I would do this directly in the action.

MVC Html.textbox/dropdown/whatever won't refresh on postback

OK, let's start with the Html.Textbox. It is supposed to contain text read from a file. The file read is based on what the user picks from a dropdown list.
The first time it is fine. The user picks a value from the dropdown list. The controller uses that value to read some text from a file, and returns that text to the view via the view model. Everything is fine.
THen the user picks another value from the dropdown list. The controller reads a new value from a file and returns it via the view model. Debugging to the LINE BEFORE THE HTML.TEXTBOX is set in the view shows that the model contains the correct value. However, the textbox itself still shows the PREVIOUS value when the page displays!
If I switch from Html.Textbox to a plain input, type="text" html control, everything works fine. That's not so hard, but the same thing happens with my dropdown list -- I can't set the selected value in code. It always reverts to whatever was chosen last. Rendering a "select" tag with a dynamically-generated option list is a pain. I would love to be able to use Html.Dropdown.
What am I missing here?? This is such a simple thing in webforms!
When you post a form, the values that are posted are put into ModelState. When the HtmlHelper renders an html iunput element, e.g. Html.TextBoxFor(x => x.FirstName), it'll search various locations to get the value for the textbox... ModelState is before ViewData.Model in the list of locations. So there for, the previously posted value will appear in your textbox.
To fix this you could clear the ModelState value or update the ModelState value. BUT I would kinda view that as a hacky way of getting around the problem.
The real issue has more to do with the flow of the posts and requests. I would personally look into that and maybe implement the PRG (Post Redirect Get) pattern.
HTHs,
Charles
Following on from what Charles/Charlino said:
Model binding updates the ModelState object, which contains validation and model binding errors that are collected during model binding.
Inside an action method, model binding has occurred already to update the model, and generated the ModelState object. If you now update the value on the model inside the action, you must also manually update the model state (since the helpers use it to generate their HTML). Below is an example:
model.CaptchaIsValid = CaptchaService.ValidateAndExpireCaptcha(model.CaptchaAttempt);
if (!model.CaptchaIsValid)
{
ModelState.AddModelError("CaptchaAttempt", "Incorrect - please try again");
}
// I'll clear the value on each attempt, to force them to re-enter a CAPTCHA.
model.CaptchaAttempt = string.Empty;
// Since I updated the model, I must create a new ValueProvider result...
ValueProviderResult clearedValue = new ValueProviderResult(
model.CaptchaAttempt,
model.CaptchaAttempt,
CultureInfo.CurrentCulture);
// ... and update the ModelState's value.
ModelState.SetModelValue("CaptchaAttempt", clearedValue);
The biggest issue I see here is that you are trying to do a postback within MVC. That model is really not supported, and is actually way more trouble than it is worth (as it seems you are finding out). I would recommend using Ajax to update the contents of the dropdown dynamically.