Cakephp add form inside modal window while in index view - cakephp

New to cakephp here.. wondering how i could have a button whilst in my index view to open an add form ( for the same model ). once i submit this form i'd like the modal to disappear and the new record to be show in the index view. I was thinking of putting the add form in a cake element? but not sure how to put this in a modal window. any advice would be great thanks.

What #savedario says makes perfect sense. I blogged about this just before Christmas and have copied the relevant bits below:
View/Users/index.php:
<!-- overlayed element -->
<div id="dialogModal">
<!-- the external content is loaded inside this tag -->
<div class="contentWrap"></div>
</div>
...
<div class="actions">
<ul>
<li>
<?php echo $this->Html->link(__('Add user', true), array("controller"=>"users", "action"=>"add"), array("class"=>"overlay", "title"=>"Add User"));
</li>
</ul>
</div>
...
<script>
$(document).ready(function() {
//prepare the dialog
$( "#dialogModal" ).dialog({
autoOpen: false,
show: {
effect: "blind",
duration: 500
},
hide: {
effect: "blind",
duration: 500
},
modal: true
});
//respond to click event on anything with 'overlay' class
$(".overlay").click(function(event){
event.preventDefault();
$('#contentWrap').load($(this).attr("href")); //load content from href of link
$('#dialogModal').dialog('option', 'title', $(this).attr("title")); //make dialog title that of link
$('#dialogModal').dialog('open'); //open the dialog
});
});
</script>
Views/Users/add.ctp:
echo $this->Form->create('User');
echo $this->Form->input('name');
echo $this->Js->submit('Save', array( //create 'ajax' save button
'update' => '#contentWrap' //id of DOM element to update with selector
));
if (false != $saved){ //will only be true if saved OK in controller from ajax save above
echo "<script>
$('#dialogModal').dialog('close'); //close containing dialog
location.reload(); //if you want to reload parent page to show updated user
</script>";
}
echo $this->Form->end();
echo $this->Js->writeBuffer(); //assuming this view is rendered without the default layout, make sure you write out the JS buffer at the bottom of the page
Controllers/UsersController.php:
function add() {
...
$this->set('saved', false); //false by default - controls closure of overlay in which this is opened
if (!empty($this->request->data)) {
$this->User->create();
if ($this->User->save($this->request->data)){
$this->set('saved', true); //only set true if data saves OK
}
}
...
}
You'll need to have included JQuery 1.9+ and JQuery UI js files in the layout used by your index.ctp and add.ctp.
Actually I have now switched to Bootstrap modals in my own code because I think they look nicer but the approach is very similar.

CakePHP does not have a built-in functionality to do what you want.
Using Elements here does not necessarily help, unless you find yourself writing the same code in different places...
I could not find anything already written to handle this, so I wrote my own javascript functions that work but I doubt could be used as a plugin.
To explain the whole thing would be a bit too long here.
I suggest you start looking at Jquery UI Dialog.
Your index view will need an 'onclick' on the 'add' action button to open the dialog.
The content of the dialog itself could come from the same add() action you would normally use, loaded via an ajax call.

I used bootstrap 3 for my cakephp project which included modals, but that may be overkill for your project.

You have to use bootstrap or jquery to do this. CakePHP does not have a built-in functionality to do what you want.

Typo
<div class="contentWrap"></div>
must be
<div id="contentWrap"></div>
or
$('#contentWrap').load($(this).attr("href"));
must be
$('.contentWrap').load($(this).attr("href"));

Related

HandsOnTable editor custom function

I'm using the autocomplete editor of HOT, but needed to have my own template of the option-list. I've been able to accomplish that, by removing the default display and replacing it with my own while doing a lazy load of its content. But I need to perform specific tasks on each of the options being clicked.
The issue is that I cannot find a way to have my <a ng-click='doSomething()'> or <a onclick = 'doSomething()'> tags to find my "doSomething" function.
I've tried the extend prototype of the autocomplete instance, have put my function out there on my controller to no avail. Is there any way I can insert a delegate function inside this editor that could be triggered from inside my custom-made template? (Using angularjs, HOT version 0.34)
Dropdown options cannot interpret HTML instead of Headers.
To perform action when an option is selected you can use Handsontable callback : AfterChange or BeforeChange
Here you can find all HOT callbacks https://docs.handsontable.com/0.34.0/tutorial-using-callbacks.html
This JSFiddle can help you http://jsfiddle.net/fsvakoLa/
beforeChange: function(source, changes){
console.log(source, changes)
},
afterChange: function(source, changes){
console.log(source, changes);
if(!source) return;
if(source[0][1] == 0){//if ocurs on col 0
let newsource = optionsWBS[source[0][3]];
cols[1] = {
type : 'dropdown',
source: newsource,
strict: false
};
hot.updateSettings({columns: cols});
hot.render();
};
}
Thanks, I actually needed actions specific to each area being clicked. What I did to make it work was this: while inserting the items for the list, I created the element and bound it to the function right away: liElement = document.createElement('li') .... liElement.onclick = doSomething(){} .... got it working this way ..

Animate Angular-flash Alerts

Using the package, Angular-flash and having issues adding custom animations to the showing and hiding of an alert.
From the docs
If you want to use animations, include ngAnimate module. You can then
use regular Angular animation technique for applying your own
transitions.
.alert {...}
.alert.ng-enter, .alert.ng-enter.ng-enter-active {...}
.alert.ng-leave, .alert.ng-leave.ng-leave-active {...}
I feel like I've tried all possible combinations but struggle to get the in . out effects.
My HTML
<flash-message>
<div>{{ flash.text }}</div>
</flash-message>
<button ng-click="showFlash()">PRESS ME</button>
Controller
$scope.showFlash = function() {
var message = '<strong>Hello!</strong> ';
var id = Flash.create('info', message, 4000, false);
};
Just to test my CSS animation is working I just added an animation to the alert class. This provides the show animation only.
.alert {
animation: 1.5s zoomIn ease;
}
I need to be able to attach it to the "Alert Show Event" and then attach a zoom out to the "Alert Hide Event", allowing a specific show and hide effect.
I've tried these in multiple combinations but struggle to find what class to associate with the show / hide animations.
.alertIn,
.alertOut
.alert.ng-hide-add-active
.alert.ng-hide-remove-active
Thanks
I developed a flash message package and uploaded it in npmjs.com, i think the package will help you,
Package Name: Flash-Text
author: VamshiDureddy

Kendo tooltip content is not updated when angular model is changed

I have defined kendo tooltip in following way:
<i class="fa fa-info-circle ico-tooltip" kendo-tooltip k-content="model.Description"></i>
Initially the content is ok, but when model.Description is changed and the site is not reloaded the k-content shows the old value.
After reload site by F5 there is new value, but this is not what I want to achieve.
It is possible to somehow refresh this tooltip or workaround this issue?
I had a similar issue and I debugged through Kendo's code and following solution works, in my case I wanted to show only upto 22 characters of text from my model and show full text in the tooltip, here is example code
This sample below is using Angular's 1.5 component
<div kendo-tooltip="$ctrl.selectedItemTooltip" k-content="$ctrl.selectedItemText">{{$ctrl.selectedItemText | limitTo:22}}</div>
and in JS
function fetchFromServer(){
$http.get('/myService').then(function(response){
ctrl.selectedItemText = response.data.model.text;
ctrl.selectedItemTooltip.options.content = ctrl.selectedItemText
ctrl.selectedItemTooltip.refresh();
});
}
in the tooltip options object (when you initialize the tooltip) you set function for the hide event (check documentation ) and in this function you could call refresh function
`
var tooltip = $("#container").kendoTooltip({
hide: function() {
tooltip.refresh();
}
})
`
i think this will do the trick

How to clear kendo window data using refresh method?

I have form and grid in kendo window modal, I want to refresh the screen everytime user open the modal window, I have used refresh() but its not working...any suggetion will be appreciated....
So far tried code...
main.html
<div kendo-window="viewAttestorkWin" options="attWinOptions" k-modal="true"></div>
main.js
$scope.openAttestorSearch = function(){
$scope.viewAttestorkWin.refresh();
attestorConfig.attestorModalWinConfig.title = 'Add Attestor(s)';
$scope.viewAttestorkWin.setOptions(attestorConfig.attestorModalWinConfig);
$scope.viewAttestorkWin.open().center();
};
It should work properly with your code right now, yet I suspect setOptions make it didn't. Have you try to call the refresh method after window is open?
$scope.openAttestorSearch = function(){
attestorConfig.attestorModalWinConfig.title = 'Add Attestor(s)';
$scope.viewAttestorkWin.setOptions(attestorConfig.attestorModalWinConfig);
$scope.viewAttestorkWin.refresh().center().open();
};

Unable to render a Ext.form.TextField into the output of an XTemplate

I want to render some Ext components into the output of an XTemplate. We want to have the flexibility of using an XTemplate to render the HTML but retain the styling, behaviour, and handlers of using Ext components rather than plain old HTML elements.
I am currently successfully doing this with an Ext.Button. In the template I am writing a placeholder div like so:
<div id="paceholder-1"></div>
After I have called apply() on the template I then create a new Ext component and render it in like so:
this._replacePlaceholders.defer(1, this, [html, 'placeholder-1', collection]);
The _replacePlaceholders function looks like this:
_replacePlaceholders: function(html, id, collection) {
var emailField = new Ext.form.TextField({
emptyText: 'Email address',
hideLabel: true
});
var downloadButton = new Ext.Button({
text: 'Download as...',
icon: 'images/down.png',
scope: this,
menu: this._createDownloadOptionsMenu(collection) // Create Menu for this Button (works fine)
});
var form = new Ext.form.FormPanel({
items: [emailField, downloadButton]
});
downloadButton.render(html, id);
}
This works and renders the button into the html correctly. The button menu behaves as expected.
But if I change the last line of replacePlaceholders to emailField.render(html, id); or form.render(html, id); I get a javascript error.
TypeError: ct is null
ct.dom.insertBefore(this.el.dom, position);
ext-all-debug.js (line 10978)
I'm a bit confused because from what I can tell from the docs the render() method called is going to be the same one (from Ext.Component). But I've had a bit of a play around and can't seem to track down what is happening here.
So is there any good reason why these components behave differently from Ext.Button? and is it possible to render an Ext.form.TextField or an Ext.form.FormPanel or anything that will let me use an Ext text field in mt XTemplate html?
NB. I am using ExtJS 3.3.1 and don't have the opportunity to upgrade the version. I believe ExtJS 4 has functionality which would make doing what I doing much easier.
Thanks!
Solution is quite simple - use form.render(id) instead of form.render(html, id).
See [api][1] if you have doubts.
The reason why button is rendering properly is that it has weird onRender implementation, different from Component.
onRender : function(ct, position){
[...]
if(position){
btn = this.template.insertBefore(position, targs, true);
}else{
btn = this.template.append(ct, targs, true);
}
[...]
}
As you can see in code above, if you provide position (which is basically second argument provided to render) it doen't use ct (which is first argument passed to render).
In normal component onRender method looks like this:
onRender : function(ct, position){
[...]
if(this.el){
this.el = Ext.get(this.el);
if(this.allowDomMove !== false){
ct.dom.insertBefore(this.el.dom, position);
if (div) {
Ext.removeNode(div);
div = null;
}
}
}
}
In code above, you can see, that ct is called always, despite the position is not null.
The bottom line is that rendering of button works by accident.

Resources