I'm making a website using spring security and grails 3.1.10. In this site I'm listing all image from database and show them at index. The problem is when I tried to edit one of those image. For example I want to just edit name but if I do not select an image this field become null.But I want to protect the image. How can i through this.
edit gsp
<div class="col-xs-2 col-sm-2 col-md-2">
<input type="file" class="form-control" name="productImage" id="productImage">
</div>
I tried to write a controller to protect old one but this one not work.
def id=params.id
Product old=Product.findById(params.id)
def f = request.getFile('productImage')
if(f.empty){
print("file is empty")
if(old.productImage){
println("there is a file in database")
product.productImage=old.productImage
}}
I think I kind of understand there are a few issues here:
//These two are the same
Long id=params.id ? params.id as Long : null
Long id=params.id ? params.long('id') : null
It says
Long id= (is there a params.id )
{ yes ? } -> params.id as Long {otherwise :} -> null
findById should be used in rare cases:
//You should never use findById unless an example would be findByIdAndSomethingElse(id,somethingElse)
// Product old=Product.findById(params.id)
Instead you should use (look int get read and load) get is the best since it ensures the record actually exists and where as read could return a cached copy (that may since be removed) (read load are less resource intensive) worth reading up about - so sticking with get : and you may not have id so it should be wrapped around a further
if (id) {
// Product old=Product.get(id)
// Product old=Product.read(id)
// Product old=Product.load(id)
// You could have just done this which should convert params.id as long itself as the method
Product old=Product.get params.id
def f = request.getFile('productImage')
if(f.empty){
print("file is empty")
if(old.productImage){
println("there is a file in database")
//I think this may be the issue:
product.productImage=old.productImage
//should this not be ?
product=old
}}
you have now outlined what old or product do after your statement which is the reason for my comment.
Does product or old then get sent as variables to the gsp page how are they represented ?
Also if this is your edit form;
<div class="col-xs-2 col-sm-2 col-md-2">
<input type="file" class="form-control" name="productImage" id="productImage">
</div>
This is missing value
<input type="file" class="form-control" name="productImage"
value="${someParams?.value}" id="productImage">
You state it returns null so it must be some other form field that you have not provided since this field actually has no value defined and therefore can never be a null.
Also notice
value="${someParams?.value}"
vs
value="${someParams.value}"
The ? is protecting the field from returning a null value. So upon start of a form where there may not be a value that would then save it showing null on the user's screen.
With all that said there appears to a be a conflict in what you say something going null vs what you are trying to set etc.. maybe a clash in what you want or maybe an easier way of putting it all
def f = request.getFile('productImage')
if (f.empty) {
if (params.id) {
Product old=Product.get(params.id as Long)
print("file is empty")
if (old.productImage) {
println("there is a file in database")
product.productImage=old.productImage
} else {
//what should produce.productImage be now if no file and nothing on db ?
}
} else {
//what should happen if there is no product.id ?
}
} else {
//what happens when there is a file provided - should that Product check be outside of this loop entirely should that file being returned be merged with the existing record ?
}
There is lots there that will hopefully help you understand what is going wrong. With that all said this sort of stuff should really be done with the aid of a validation class this saves on you having to code out lots of logic in your controllers that in the end looks all too long winded and messy and hard to follow.
I will update an example project: https://github.com/vahidhedayati/grails-bean-validation-examples a bit later today with an image example. Hopefully with a video to explain what I have added. Will leave a comment on here when done.
Related
I am in the following situation and have the following problems.
I am developing an application that reads data from a .json file. I store this data in rows. Now the .json files can be different and therefore I have to cover every case (there are many cases). If a tag is not present in the .json, this row should not be displayed.
Now it can happen that I have covered a case which searches for data.test.person but data.test is not present in the JSON.
A case could look like this:
<TestAntragsdatenAbschnitt
title={"Test"}
value={data.test}>
<TestAntragsdatenRow
label1={"Person"}
value1={data.test.person}
/>
</TestAntragsdatenAbschnitt>
This is my component.
export default class TestAntragsdatenAbschnitt extends React.Component {
value;
title;
render() {
this.value = this.props.value;
this.title = this.props.title;
return (
<>
<h4 className={"antragsdatenAbschnitt"}>
{checkAbschnitt(this.title, this.value)}
</h4>
{this.value != null &&
this.props.children
}
</>
);
}
}
With the query this.value != null && I have tried to work around the error.
The error I get: TypeError: Cannot read property 'person' of undefined
My question now is, how can I query JSON tags if they exist, if so the rows should be checked. If not all rows with this tag should be skipped.
Object.keys(data).includes('test')
can be a way of checking if json object has the property.
There are a lot of other ways as well. You can also try:
value1={data.test ? data.test.person : 'error'}
kind of approach for safe null-checking
There are a couple of things wrong with your code, but let's try to unpack everything:
You're passing two props, title and value to your component named TestAntragsdatenAbschnitt. This you should receive in props, and therefore there's no need for you to store them in fields (this.value = this.props.value) for example.
Rather, just do this in the render function:
const {title, value, children} = this.props;
And now you don't need to use this.title and this.value, but just title and value.
OK we got that out of the way, now let's figure out why your optional key isn't working:
Now you should be rendering your children like this:
{children}
Now you need to conditionally render particular rows, and this shouldn't be done here in this component at all. This should be done in the component that's rendering TestAntragsdatenAbschnitt (first component you wrote in the post).
So you'd do something like this:
<TestAntragsdatenAbschnitt
title={"Test"}
value={data.test}>
{data && data.test && data.test.person ? (
<TestAntragsdatenRow
label1={"Person"}
value1={data.test.person}
/>
) : (
<p>data.test.person is not valid</p>
)}
</TestAntragsdatenAbschnitt>
As you can see, I check with the ternary operator if data.test.person is not null, if it isn't then just render the row, if not then just do something else you'd like.
You could do this in other component, but this way it's way cleaner in my opinion.
Is there a way to disable the 'remove-the-plural-s' feature in Postgraphile?
I have a table OS in my database and am using the very awesome Postgraphile library to create a GraphQL interface for free. Everything is great, but Postgraphile is truncating my table name, thinking it is plural. So I get allOs instead of allOses and createO, updateO, etc...
I tried:
Adding an underscore after the table name, and then it just retains the entire thing with an underscore.
Adding an underscore (O_S) and then the plural has capital-s allOS but the singular is O_
A smart comment specifying E'#name os' but it still drops the s
A smart comment specifying E'#name oss' which then pluralizes correctly allOsses (haha) and keeps both for the singular oss
PS in case you see this Benjie/other contributors, your documentation is incredible and the library will save me months of work.
This change is performed by PostGraphile's inflector; however it doesn't always get it right (e.g. in this case) but fortunately it's possible to override it with a small plugin.
In this case, it's probably best to add specific exceptions to the pluralize and singularize functions; you can do this using makeAddInflectorsPlugin from our inflection system. Be sure to pass true as the second argument so that the system knows you're deliberately overwriting the inflectors.
const { makeAddInflectorsPlugin } = require('graphile-utils');
module.exports = makeAddInflectorsPlugin(oldInflectors => ({
pluralize(str) {
if (str.match(/^os$/i)) {
return str + 'ses';
}
return oldInflectors.pluralize(str);
},
singularize(str) {
if (str.match(/^osses$/i) {
return str.substr(0, 2);
}
return oldInflectors.singularize(str);
}
}), true);
I'm glad you're enjoying PostGraphile 🤘
What I want to do:
Get user input from HTML form, store input in variables within Django and perform calculations with variables.
To accomplish that, I use following code:
my_var = requst.POST.get('my_var')
To prevent having 'None' stored in 'my_var' when a Django page is first rendered, I usually use
if my_var == None:
my_var = 1
To keep it simple when using a bunch of variables I came up with following idea:
I store all variable names in a list
I loop through list and create a dictionary with variable names as key and user input as value
For that I wrote this code in python which works great:
list_eCar_properties = [
'car_manufacturer',
'car_model',
'car_consumption',]
dict_sample_eCar = {
'car_manufacturer' : "Supr-Duper",
'car_model' : "Lightning 1000",
'car_consumption' : 15.8,
}
dict_user_eCar = {
}
my_dict = {
'car_manufacturer' : None,
'car_model' : None,
'car_consumption' : None,
}
for item in list_eCar_properties:
if my_dict[item] == None:
dict_user_eCar[item] = dict_sample_eCar[item]
else:
dict_user_eCar[item] = my_dict[item]
print(dict_user_eCar)
Works great - when I run the code, a dictionary (dict_user_eCar) is created where user input (in this case None simulated by using a second dictionary my_dict) is stored. When User leaves input blank - Data from dict_sample_eCar is used.
Now, when I transfer that code to my Django view things don't work not as nice anymore. Code as follows:
def Verbrauchsrechner_eAuto(request):
list_eCar_properties = [
'car_manufacturer',
'car_model',
'car_consumption',
]
dict_model_eCar = {
'car_manufacturer' : "Supr-Duper",
'car_model' : "Lightning 1000",
'car_consumption' : 15.8,
}
dict_user_eCar = {
}
for item in list_eCar_properties:
dict_user_eCar[item] = dict_model_eCar[item]
context = {
'dict_user_eCar' : dict_user_eCar,
'dict_model_eCar' : dict_model_eCar,
'list_eCar_properties' : list_eCar_properties,
}
return render(request, 'eAuto/Verbrauchsrechner_eAuto.html', context = context)
Result: The page gets rendered with only the first dictionary entry. All others are left out. In this cases only car_manufacturer gets rendered to html-page.
Sorry folks - as I was reviewing my post, I realized, that I had a major srew-up at the last part's indentation:
context and return both were part of the for-loop which obviously resulted in a page-rendering after the first loop.
I corrected the code as follows:
for item in list_eCar_properties:
dict_user_eCar[item] = dict_model_eCar[item]
context = {
'dict_user_eCar' : dict_user_eCar,
'dict_model_eCar' : dict_model_eCar,
'list_eCar_properties' : list_eCar_properties,
}
return render(request, 'eAuto/Verbrauchsrechner_eAuto.html', context = context)`
Since I didn't want the time I spend to write this post to be wasted - I simply posted it anyway - even though I found the mistake myself.
Lessons learned for a Newbie in programming:
To many comments in your own code might result in a big confusion
Try to be precise and keep code neat and tidy
Do 1 and 2 before writing long posts in stackoverflow
Maybe someone else will benefit from this.
How can I access filteredArray in my .ts component? Because right now it is accessible only inside ng-container.
<ng-container *ngIf="(userList | filter: 'name' : value) as filteredArray">
<tr *ngFor="let user of filteredArray">
<td>{{user.name}}</td>
<td>{{user.group}}</td>
</tr>
<div>Count: {{ filteredArray.length }}</div>
</ng-container>
How can I modify the code in order to obtain what I want? Thank you for your time!
To answer your question directly: it's not possible the way you describe it. But read on.
Pipes (sometimes still called "filters") should be used only to format data, i.e. prepare it in a human-readable form. For example, the build-in date pipe can be used to transform an ISO string to a string such as "March 21st, 1995", which is how a human from the USA might expect to read the date.
The way you're using pipes is not recommended, precisely because of the question you have. You've essentially put application logic inside a template, which is an anti-pattern and beats the purpose of having easy-to-read declarative templates, which Angular uses in order to figure out how to update DOM.
You should move the filtering logic back to the class. For example, instead of setting this.userList = xxx, you could have a function which you call every time, such as this.changeUserList(xxx).
changeUserList (list) {
this.userList = list
this.filteredArray = list.filter(...)
}
You can put this logic in a setter as well, which allows you to run custom code when you write the usual this.userList = list, but you'll need a separate (usually prefixed private) property on the class where you'd actually store the value. It's not really a limitation since you can also have a trivial getter, so you can still us this.userList normally as a getter without having to remember to use this._userList, essentially tucking this away as the get/set pair's implementation detail.
private _userList
public set userList (list) {
this._userList = list
this.filteredArray = list.filter(...)
}
public get userList (list) { return this._userList }
Observables could really come in handy here as well, since you could just rx.map the userList$ to filteredArray$ with an Array#filter.
public userList$
public filteredArray$ = this.userList$.pipe(map(arr => arr.filter(...))
Then in the template, you can use the async pipe.
*ngIf="filteredArray$ | async as filteredArray"
Avoid doing the following.... but it works for demo purposes 😃
Create a component (e.g. demo-element.component.ts) that takes a single #Input() value:any
Add this new component as the first child of the <ng-container>, and give it a template reference #containerRef e.g.:
<ng-container *ngIf="(userList | filter: 'name' : value) as filteredArray">
<demo-element #containerRef [value]="filteredArray"></demo-element>
In your main component, add
#ViewChild('containerRef') ref;
ngAfterViewInit() {
this.filteredArray = this.ref.value; // Terrible pattern, but answers the question:-)
}
I hope this below code will help you.
<div class="rsrvtn_blk" *ngIf="(items | fSearch:firstname) as filteredItems">
<div class="col-md-3 pl-0" *ngFor="let item of filteredItems">
// you can display the filtered content here
</div>
</div>
I have this code.I want to have some rows in JSON,to find it Im trying to use criteria. I want render each case as json.
Example: I want the row of my table that have Name:"pepito" .if I put params.nombre, but I want this only this row in JSON how can I do that?
Im trying to do that with findbyNombre(params.nombre) but if I put some if/else with his conditions it doesnt found.
Please,can somebody help me????I have to give my code for a job and Im lost!!!
THANKS!
case "GET":
def criterios=CatalogoJson.createCriteria().list() {
if (params.nombre) {
eq('nombre', params.nombre)
// render CatalogoJson.findByNombre(params.nombre)as JSON
}
if(params.id) {
eq('id', CatalogoJson.findById(params.id))
}
}
render criterios as JSON
break
I might not have got the question correctly as to what is expected. My assumption is that, you would have either of the params (either nombre or the Id or both) available in the request. Based on that assumption you can have the criteria implemented as below. Note:- I used toInteger() as you mentioned the datatype as int, generally ids are Long in conjunction with GORM and Hibernate persistence layer.
def criterios = CatalogoJson.createCriteria().listDistinct {
if(params.id) {
idEq(params.id.toInteger())
}
if (params.nombre) {
eq('nombre', params.nombre)
}
}
render criterios as JSON
UPDATE
Ok let me try this one more time. Again if I have followed you incorrectly, let me know.
The way you are expecting to map url is not RESTful. Instead, there is one best way to implement what you are expecting in the REST service:-
Pleasant way OR I-like-it-this-way
The url mapping should look like
"/catalog/$id?"(resource: 'catalog')
//Controller Action:-
def show(){
def criterios = CatalogoJson.createCriteria().list {
if(params.id) { //check 1
idEq(params.id.toInteger())
} else if(params.name) { //check 2
eq('name', params.name)
} else if(params.year){ //check 3
eq('year', params.year)
} else if(params.others){ //check 4
eq('others', params.others)
} //so on an so forth //Can also use Switch case if you want
}
render criterios as JSON
}
Use case:-
http://mydomain.com/catalog/134 --> should set the id to 134 and check 1 will be evaluated
http://mydomain.com/catalog?name=Pep --> should set the name to Pep and check 2 will be evaluated
http://mydomain.com/catalog?year=1987 --> should set the year to params as 1987 and check 3 will be evaluated
Inference-
Use of named query parameters to itemize your parameters with respect to your need in REST service and domain. If you want to use unnamed parameters then the url mapping would look like:
"/catalog/$id/$name?/$year?/$others?"(resource: 'catalog')
The problem in this approach is that your url should look like
http://mydomain.com/catalog/134
http://mydomain.com/catalog/134/Pep
http://mydomain.com/catalog/134/Pep/1987
Your optional parameters are no more optional. Have a look at Optional Variables in URL mapping