center form content modifying form.html template - atk4

I'm still using 4.1 and I'm trying to center a form content on screen.
When I add a new form it stays on the "left" of the screen.
I've tried to change form.html (temmplates/shared) adding a div with a style like this:
margin-left : 10%; margin-right : 10%;
up next to the form tag and closing it at the bottom.
The form goes to the right but not centered at all.
Anyone has any clue to help with this ?
Here is a screenshot of a simple Form (it's not basec on models)
thanks
Alejandro

Ok - i've gone to a default of atk4.2 to demonstrate.
If you add a new page with defaults as follows
<?php
class page_test extends Page {
function init() {
parent::init();
$p=$this;
$f=$p->add('MVCForm')->setModel('Customer');
}
}
?>
I get the following and the fields extend across the whole width of the page.
This is because the default page template takes the whole width and is expected.
In order to adjust the form, you can use view functionality so create a view under the /lib/View directory called Centre.php and put the following code in it
<?php
class View_Centre extends View {
function init(){
parent::init();
}
function defaultTemplate() {
return array('view/centre');
}
}
?>
Then create a new template for the view in yoursite/templates/default/view called centre.html and insert the following html code
<div style='width:50%; margin: auto;'>
<?$Content?>
</div>
and then in the page, we add the view first and the form into the view rather than straight into the page.
<?php
class page_test extends Page {
function init() {
parent::init();
$p=$this;
$v=$p->add('View_Centre');
$f=$v->add('MVCForm')->setModel('Customer');
}
}
?>
and this results in the following web page
The base ATK4 form is itself a view which means you can style the form however you want so if you get for example use a different style of form such as the one described here you can do this by copying yoursite/atk4/atk4/templates/shared/form.html to yoursite/atk4/templates/shared.form.html and changing the second line from
<?form?>
<div id="<?$_name?>" class="atk-form <?$class?>" style="<?$style?>">
<?$hint?>
<form class="<?$form_internal_class?>" id="<?$form_name?>" name="<?$form_name?>" action="<?$form_action?>" method="POST" <?$enctype?>>
<fieldset class="<?$fieldset?>">
to
<?form?>
<div id="stylized>" class="myform <?$class?>" style="<?$style?>">
<?$hint?>
<form class="<?$form_internal_class?>" id="<?$form_name?>" name="<?$form_name?>" action="<?$form_action?>" method="POST" <?$enctype?>>
<fieldset class="<?$fieldset?>">
Create a new form.css file in yoursite/templates/default/css which contains the styling
Copy yoursite/atk4/templates/shared/shared.html to yoursite/templates/shared/shared.html and add an extra tag
<?$css_include?>
just above the existing
<?$js_include?>
and in Frontend.php, let every page find the new css file.
$this->addLocation('templates',array(
'css'=>array(
'default/css',
),
));
$this->template->appendHTML('css_include','<link type="text/css" href="'.$this->api->locateURL('css','form.css').'" rel="stylesheet">');
which results in a styled form like this

There are some examples of different form layouts here that you can use to adjust the form layout itself. Not sure from your question if you want to center the form in the page or centre the fields.
If you just want to centre the Form within the webpage, you want to use margin: auto for centering css rather than setting a percentage on each side as shown here
Also note, if you amend files from the atk4 directory, you should make a copy into yoursite/templates/shared and amend it there so you can upgrade by overwriting the atk4 directory later without losing anything.

If i use the default form template (in this case in a CRUD), i get the following
If i make your change to the atk4/templates/form.html by adding
<div style="width: 50%; margin: 0 auto;">
as the second line in form.html and adding the corresponding
</div>
one line from the bottom, it shifts everything slightly to the right as follows
What is unclear in your question is what you are trying to achieve - do you want to move the fields within the form or do you want to centre the whole form on the page ?
I think the reason for the shifting is because of setting the width to 50% but I dont know what layout you are trying to obtain - do you just want to right align the labels to the fields maybe ? Please post screenshots in the original question of what you are getting and try to describe what you want to achieve.

Related

How to dynamically populate tailwindcss grid-cols-x property?

I am currently working on a page using NextJs and TailwindCss. The user has the ability of loading an image locally and setting the number of pieces horiz/vert (rows/cols) that they wish the image to be split in. To properly display this, I need to set the grid to the proper number of columns in the parent element.
I have an API I call locally that uses sharp to perform the split and calculate the width and height and I sort the images in my array so that they are in order since it is async. I then also generate a dynamic class string that just populates the proper number of columns for later assignment to my parent grid elements class.
CLASS STRING POPULATION
const gridClass = `grid grid-cols-${numCols} gap-2 pt-2`;
//*** At this point, the value of gridClass, if columns were set to 3, using template literals is :
'grid grid-cols-3 gap-2 pt-2'
//The proper string is now populated and passed back in the API response via classCss key
res.status(200).json({ msg: 'Success splitting', tileData: tiles, classCss: gridClass})
PAGE SNIPPET:
<div id="final">
<div className={tileCss} > //<--This is where I pull in the generated class string
{
imageData.map((nft, i)=>(
<div key={i} className='border shadow rounded-x1 overflow-hidden'>
<Image src={nft.imgSrc} alt="image" layout="responsive" width={nft.tileDimX} height={nft.tileDimY}/>
</div>
))
}
</div>
</div>
This sometimes works but other times it doesn't. Usually if I set the columns to 3, it seems to work properly, but if I set it to 5 lets say, regardless of the input image size, it just puts them all in a single column with large images. Oddly however, the parent grid class on the page is correct, it just seems that it isn't adhered to. I will provide some snapshots below to show what I'm talking about. I've been trying to figure this out for a couple days, however I haven't had luck and since I'm new to NextJs I thought I would share here and see if I'm just doing something stupid. Thanks!
The below results also don't seem to care if the viewing window is stretched wide or reduced in size. I just took the snapshots below so that you could see what was happening in a smaller viewing window.
This is the expected result where the image columns should match the columns entered by the user:
Notice how the css class shows up under styles as well:
This is the improper result, where the user selected 5 columns, the image was split into the correct number of columns, but the display of this in the front end grid does not follow the css.
As you can see grid-cols-5 is correct from a class standpoint, but the viewed result doesn't adhere to this.
Grid-cols-5 is in html class but missing under styles applied:
So I finally found the source to the issue. It seems that tailwindcss performs an optimization on classes brought in and if you are not using the class anywhere in your html, it doesn't include those classes. So I not only needed to return my dynamic string with the expected class, but I also needed to add all the classes I would possibly be using into my tailwind.config.js file under the safelist key.
So my config now looks like this and it is working as expected:
module.exports = {
content: [
'./pages/**/*.{js,ts,jsx,tsx}',
],
safelist: [
{
pattern: /grid-cols-./,
}
],
theme: {
extend: {},
},
plugins: [],
}
More information can be found here:
https://tailwindcss.com/docs/content-configuration#using-regular-expressions
Thanks again Mohit for your assistance.
One of the problem I noticed is in grid-cols-${numCols} in the line
const gridClass = `grid grid-cols-${numCols} gap-2 pt-2`;
TailwindCSS doesn't allow you to generate classes dynamically. So when you use the following to generate the class… grid-cols-${numCols} as a string.
…TailwindCSS will not pick that up as a valid TailwindCSS class and therefore will not produce the necessary CSS.
You can use the function from where you are getting numCols and instead of returning the value of numCols, simply return grid-cols-${numCols}.
Suppose let say your function be getNumofCols(), then modify it like this
function getNumofCols() {
...
...
...
...
...
return "grid-cols-" + numCols ;
}
So that it returns the complete string .
And use it like again
const gridClass = `grid ${getNumofCols()} gap-2 pt-2`;
If your function uses any parameter then you can create a new function and call this function and just add grid-cols- to the return value.
By doing it this way, the entire string for every class is in your source code, so Tailwind will know to generate the applicable CSS.

How do I dynamically style uib-accordion-group

I have created a uib-accordion in my Angular website and can get most of the functionality I want, with dynamic content changing accordingly.
I am having trouble styling the uib-accordion-group dynamically.
<uib-accordion-group panel-class="panel-danger">
<uib-accordion-heading>
Accordion Heading 1
Is fine and colours the whole heading Red/Pink, I want to change this to panel-warning or panel-info based on other variables on the page.
<uib-accordion-group panel-class="{{getPanelColor()}}">
<uib-accordion-heading>
Accordion Heading 1
The function seems to be called correctly and is triggered correctly with ng-click elsewhere.
I appears that I cannot change the value panel-class uses dynamically. So in this instance getPanelColor() returns 'panel-danger', 'panel-info' or 'panel-warning' depending on other variables. If I print this return value out on the page in another div or whatever it changes correctly. If I refresh the page the correct colours are displayed for the changed panel-group.
Is there another way of setting the color - I don't know what the classes are for the accordion-group. I have tried changing the color of a div withing the panel, but this is a child element and does not change the color of the whole heading.
Any help much appreciated. (I'll come up with a JSFiddle if the question is not clear)
If you look at the HTML after the panel-class has changed and Angular has digested the change, you will see this line:
<div class="panel panel-danger" ... panel-class="panel-default">
That is, there is a mismatch between class and panel-class (the former has panel-danger, whereas the latter has panel-default). The uib-accordion-group directive simply does not handle the change in the wanted manner.
One workaround is to add ng-if to the whole group:
<uib-accordion-group ng-if="render" panel-class="{{getPanelColor()}}">
... and just before you want to change panel-class, remove the whole element temporarily, so that Angular re-renders it from scratch. Hopefully, the following code explains the principle:
$scope.render = true;
$scope.panelColor = 'panel-danger';
$scope.setPanelColor = function(val) {
$scope.panelColor = val;
$scope.render = false;
$timeout(function () {
$scope.render = true;
});
};
$scope.getPanelColor = function() {
return $scope.panelColor;
};
See the proposal in action: http://plnkr.co/edit/XfJiPnNi1z4F9cgIVxxw?p=preview. Press 'Clear panel color OK'.
The downside is that the removal of the element causes some flickering.
I have added another button 'Clear panel color FAIL' that shows what happens in your failing case. Here is what the HTML looks like after you press the button, notice the mismatch panel-danger vs. panel-default:
Use an interpolated expression in the class attribute, for example:
class="{{!ctrl.valid?'notValid':'valid'}}"

Using angular to change class settings

There is a lot of information on how to use ng-class and ng-style on elements. But I was wondering if there is a way to use angular to change the "settings" of a class.
So for example, say that you had a css class that looked as follows:
.testclass {
color: red;
background-color: blue;
}
I want to use angular to change the color:red to color:black, without attaching angular to the HTML DOM object, but via the class instead.
OK, this isn't a very useful example. What I was really planning to use it for was to hide part of ck-editor (class cle_top) and I want to set the whole class to hidden when someone clicks a button (and visible if the click it again).
======== To make it clearer, this is the bit of HTML I want to hide =======
<span id="cke_1_top" class="cke_top cke_reset_all" role="presentation" style="height: auto; -webkit-user-select: none;"><span id="cke_8" class="cke_voice_label">
Editor toolbars</span><span id="cke_1_toolbox" class="cke_toolbox" role="group" aria-labelledby="cke_8" onmousedown="return false;">
<span id="cke_11" class="cke_toolbar" aria-labelledby="cke_11_label" role="toolbar"><span id="cke_11_label" class="cke_voice_label">
But I need to do it without being able to add angular hooks in the HTML code (like adding ng-class to the span, which would have been a simple solution)
Attached is a JSfiddle that shows my problem, and as you can see, the toolbar button does nothing.
http://jsfiddle.net/vrghost/uqvo3ceh/
Which kind of works now, it adds the class invisible to the span, however, it does not hide the span that it is looking at.
Use the same process on a test text and it works...
Don't know of anything that will edit the class itself, but that probably isn't want you want to do. Other options are:
1) Create a second class, that comes after the first one in your CSS file that adds / changes the properties you want. Ex:
.testclass {
color: red;
background-color: blue;
}
.newclass {
color: green; // change property in first CSS class
display: none; // or hide
}
Then apply the second class conditionally:
<div class="text-class" ng-class="{newclass: hideScopeFlag}">blah</div>
2) Simply use ng-if, ng-hide, or ng-show if all you are doing is hiding something. Ex:
<div class="text-class" ng-hide="hideScopeFlag">blah</div>
or
<div class="text-class" ng-show="!hideScopeFlag">blah</div>
Why not simply toggle the class off/on for that element when the user clicks the button? (Edit: You said you want to "set the whole class to hidden" - I am assuming you mean to remove the class?)
To answer your question though, you can do this with JavaScript using document.styleSheets.
See this Stack Overflow question and the blog post it references. It mentions that there may be some browser compatibility issues. I have not investigated this.
EDIT: This implementation of 'ng-toggle' will allow you to hide or show an element with a single button.
The simplest solution without messing with the stylesheets is to add a new rule like
.visibleOff .testclass {
color: black;
}
and then you just need to toggle the "visibleOff" class on a parent element (the wrapper or the body element) of the editor.
To hide certain elements in the DOM you can also use a $scope variable that acts as a boolean. You can set it to false by default and on button click toggle it to true and back.
$scope.hidden = false;
$scope.toggleHide = function(){
$scope.hidden = !$scope.hidden;
}
In your dom you can then wrap your element with an ng-hide="hidden" attribute like so:
<div ng-hide="hidden">...</div>
<button ng-click="toggleHide()">togglehide</button>
A plunker example can be found here: http://plnkr.co/edit/?p=preview
If anyone wanted to know how to do this, potentially this could be useful for other things as well.
Created a function that uses document.querySelector to find the element, then just do a toggle to turn on or of, and that, as they say, is it folks.
$scope.toolBarVisible = function(){
console.log("Changing visibility");
var element = document.querySelector( '.cke_top' );
console.log("Just to do some debugging we check " + element);
var myEl = angular.element( element );
myEl.toggle();
element = document.querySelector( '.cke_bottom' );
myEl = angular.element( element );
myEl.toggle();
var myEl2 = angular.element( document.querySelector( '.test' ) );
myEl2.toggleClass("invisible")
}
And for those that are looking closely, yes, it hides the bottom as well, and all without changing ckeditor or the code.
Hope someone finds it helpful.

backbone js add printing region dynamically

I have a requirement to print the View model data using Print Button.
Currently i have a div and assigning my view content to it. This div has been already added in backbone region. In my javascript function, i am just setting the viewmodel content to the printdiv and it working with out any issue.
But the content which i have added for printing is getting appended in the browser HTML also, I dont want to show that in my browser. I tried setting visible hidden and display none to my printingdiv. but then printing is not working since the content is not visible
CSHTML:
<div id="printdiv"/>
JS:
Myapp.printdiv.show(viewData.view);
window.print();
Init.JS
Myapp.addRegions({
printdiv: '#printdiv',
});
Please help me to resolve this issue
Thanks
The best way to handle this sort of problem is with a print-specific stylesheet. This article explains how to do that in detail, but the short version is that you define your non-print styles as normal, then use CSS code like the following to override print-specific styles:
#printdiv {
display: none
}
#media print {
#printdiv {
display: block;
}
}

Allow html in input default value

Just a quick question..
I am trying to generate an text input where the default value is nested in tag with an inline css..just to make it look smaller and grayer than the normal input.
echo $this->Form->input( 'address', array('div'=>false, 'label'=>'', 'default'=>'<span style="font-size: 0.6em;color:#e3e3e3;">put your address here</span>', 'size'=>'50' ) );
after the user would click, the default value would be erased leaving it blank.
However cakephp generates the input with the value containing the html tags, i.e. .
How do I make cakephp unfilter the html in the default value?
I forgot what option to use in this situation and I tried everything that I can think of. I remember that I can do this by just adding some sort of value in the option array like 'html'=>false.
Put your helper text in your labels. If you put the default value as a HTML string the Input will display the HTML as it does not render HTML inside of it.
If you add the additional HTML to your label, you could use this http://trevordavis.net/blog/jquery-inline-form-labels to overlay the labels over the inputs.
echo $this->Form->input( 'address', array('div'=>false, 'label'=>'put your address here','size'=>'50' ) );
Also, this method allows you to apply the css externally instead of inline -- which is always best.
I am not aware of any way to get an input box to render html inside itself. There is also nothing in the API to suggest what you want. It is possible to embed it within a div, and to include things before, after, and between the label and input. I think you need to use javascript to accomplish what you want to do.
<style>
.default {font-size: 0.6em;color:#e3e3e3;}
.normal {color:black;}
</style>
<script language='javascript'>
function change(input)
{
input.classList.add("normal");
if (input.value == "enter text here")
input.value = "";
}
</script>
<form>
<input id='test' class='default' type='text' value='enter text here' onfocus='change(this);'>
</form>

Resources