Grails- How to display the last uploaded image? - grails

I used to displayed more than one picture, hence I used the each. Now I have to display only the last uploaded picture. How should I changed my code?
<g:each in ="${statusMessage?.fetchProductPictureUrls() }" var="picture">
<div class="feed-picture">
<div class="fl">
<img class="single" src="${picture }" alt="Product Picture">
</div>
</div>
</g:each>

You can do this by many ways, here are 2:
1 - Filter the desired image in your controller, service or presenter and in your .gsp you just need to access your image variable.
2 - Use a tagLib to do this (not tested):
class LastImageTagLib {
static namespace = "last"
def image = { attr ->
//filter your image
def lastImage = attr.images.last()
out << "<img class='single' src='${lastImage}' alt='Product Picture'>"
}
}
And in your .gsp:
<div class="feed-picture">
<div class="fl">
<last:image images="${statusMessage?.fetchProductPictureUrls()}" />
</div>
</div>
I think the first option is better.

So going on the code above I am unsure if the list "fetchProductPicturesUrls" is sorted or not.
If it is, you have a few options.
You can grab the last entry of the list by leveraging the .last() method.
http://groovy.codehaus.org/groovy-jdk/java/util/List.html
OR
You can grab the list size and track the count by setting the status flag in your foreach loop.
http://grails.org/doc/latest/ref/Tags/each.html
Suggestion:
I would recommend storing images on disk or in the cloud vs storing them in the database.
A nice way to maintain these images is to create a domain. Here is a sample I use for S3 images.
class S3Image {
Date dateCreated
Date lastUpdated
String imageUrl
String imageName
static constraints = {
imageUrl(blank:false)
imageName(blank:false)
}
}

Related

Can't get gridsome g-image to work for grid of thumbnails

This is for the front page.
I've made an image collection in gridsome.server.js by scanning a folder full of images and creating nodes, each containing the name and the path of the image:
let dir = fs.opendirSync(process.cwd() + '/static/images')
let fd, fn, nameParts
const imagesColl = actions.addCollection('images')
while (!!(fd = dir.readSync())) {
fn = fd.name
nameParts = fn.split('.')
imagesColl.addNode({
name: nameParts[0],
path: '/images/' + fn
})
}
dir.close()
In the title page, I'm creating a 4x2 grid of these images.
The graphql query looks like this:
images:allImages {
edges {
node {
name
path
}
}
}
and then in my vue page component, I'm using the images like this
...
<div>
<div class="grid grid-cols-4 shadow-xl">
<g-image width="100" v-for="(edge, ix) of $page.images.edges" :key="ix"
:src="edge.node.path" />
</div>
</div>
So, the collection is being created just fine, I'm able to query them in the page, but It doesn't seem like the g-image processor is getting invoked at all.
I'm specifying a width of "100", which I expect to see a grid of smallish images - but it's not happening. Basically the resulting output is just the browser sizing them down to "dumbnails" about 300px across (for this page size.)
Any thoughts appreciated.
This is a documented bug in gridsome. This comment gives a workaround for a way to fix this. I've tested this solution and it has worked for me. Copying it here directly:
Go to gridsome.config.js and add an alias for your images folder inside of the chainWebpack function (you may need to add it):
module.exports = {
siteName: 'Jeremy Jackson',
plugins: [],
chainWebpack: config => {
config.resolve.alias.set('#images', '#/assets/images')
},
templates: {}
}
Save the file and restart the server.
Then in your code where you want to use the image you can do:
<g-image :src="require(`!!assets-loader!#images/${imageUrl}`)"/>
And the dynamic image shows up. This works inside of v-for as well.
For reference, here's the code I'm using inside of a v-for in my site:
<div id="project-images">
<div class="section-header">Screenshots</div>
<div class="row">
<div
class="col-xs-12 col-sm-3 project-image"
v-for="(projectImage, index) in $page.project.images"
:key="projectImage"
#click="openLightBox(index)"
>
<g-image class="responsive-image" :src="require(`!!assets-loader!#images/${projectImage}`)"/>
</div>
</div>
</div>
Width and Height don't work with this method, here's the workaround for that:
to specify a width/height/etc you add a query string right before the path. So the example above would become:
<g-image class="responsive-image" :src="require(`!!assets-loader?width=250&height=250!#images/${projectImage}`)"/>

Randomly selecting an image from a folder in Umbraco

I have created a folder in Umbraco and I would like to display a random image from that folder on my page.
I found a solution from a few years ago which was giving me compile errors
dynamic folder = Library.MediaById(1054);
var randomImage = folder.Children.Where("nodeTypeAlias = \"Image\"").Random();
I found that I have to add the proper inherits in my file
#using umbraco.MacroEngines
#inherits DynamicNodeContext
but this it gives me an error because I already have a #model I'm using in the first line
The 'inherits' keyword is not allowed when a 'model' keyword is used.
Thanks for any help
You can take a look and learn from sample macro partial views pre-installed in each Umbraco website. There is a snippet called List Images From Media Folder.
The code of the default snippet looks like this:
#inherits Umbraco.Web.Macros.PartialViewMacroPage
#*
Macro to display a series of images from a media folder.
How it works:
- Confirm the macro parameter has been passed in with a value
- Loop through all the media Id's passed in (might be a single item, might be many)
- Display any individual images, as well as any folders of images
Macro Parameters To Create, for this macro to work:
Alias:mediaId Name:Select folder with images Type:Single Media Picker
*#
#{ var mediaId = Model.MacroParameters["mediaId"]; }
#if (mediaId != null)
{
#* Get all the media item associated with the id passed in *#
var media = Umbraco.Media(mediaId);
var selection = media.Children("Image");
if (selection.Any())
{
<ul>
#foreach (var item in selection)
{
<li>
<img src="#item.umbracoFile" alt="#item.Name" />
</li>
}
</ul>
}
}
We need to remember to add the parameter to macro if we're using them there.
Then we can use both: Media or TypedMedia helper methods to retrieve folder (which is typical media item with different type), despite of the required returned type. I usually use TypedMedia to be able to operate on strongly typed object and preview properties in Visual Studio.
If we create macro properly and insert it on the template using code like this (with proper folder ID):
#Umbraco.RenderMacro("Test", new { mediaId="1082" })
we should see a list of images from this folder (all of them at that moment).
The final part is almost the same as you previously did it, but we need to adjust it a little bit. My final code and suggestion is below:
#inherits Umbraco.Web.Macros.PartialViewMacroPage
#{
var folderId = Model.MacroParameters["mediaId"];
if (folderId != null)
{
var media = Umbraco.TypedMedia(folderId);
var rand = new Random();
var imagesInFolder = media.Children("Image");
if(imagesInFolder.Any()) {
var pick = imagesInFolder.ElementAt(rand.Next(0, imagesInFolder.Count()));
if (pick != null)
{
<img src="#pick.GetCropUrl()" alt="#pick.Name" />
}
}
}
}
Let me know if it solved your problem :)

Filter on PropertyTypeAlias in Umbraco 7

I have a Content Repository which contains 2 sections, Career Categories and Branches.
I have create for each one a filter, below you can find the code for Career categories. This is working fine. Now I want to display the amount of visible content nodes for each item of the filter.
The content node contains 2 properties which are content pickers set to only select one.
Property alias for the Career category picker is function.
This doesn't work which give me always 0, but I have created one content page. What am I missing here?
#inherits Umbraco.Web.Macros.PartialViewMacroPage
#*
This snippet takes all of the career categories to create a filter
*#
#{
// Take the content repository node
IPublishedContent contentRepository = Umbraco.ContentAtRoot().DescendantsOrSelf("ContentElements").FirstOrDefault();
// Take the career categories node
var careerCategorieRep = contentRepository.Children.Where("DocumentTypeAlias == \"ucCareersCategoryRepository\"").FirstOrDefault();
// Take the careers list content node
IPublishedContent careersList = Umbraco.ContentAtRoot().DescendantsOrSelf("CareersList").FirstOrDefault();
}
<ul class="col-md-12 col-sm-6 aside-widget-container">
<li class="widget">
<div class="title">
<h3>Beroep</h3>
</div>
<ul class="menu">
#* // Loop over the categories *#
#foreach (var careerCategorie in careerCategorieRep.Children.Where("Visible").OrderBy("Name").ToList())
{
// Here I need to filter on the career category to get the amount of visible nodes in the content
var count = careersList.Children.Where("Visible && function == " + careerCategorie.Id).Count();
<li>#careerCategorie.Name<i class="fa fa-angle-right"></i></li>
}
</ul>
</li>
</ul>
UPDATE
The problem is in this line of code:
var count = careersList.Children.Where("Visible && function == " + careerCategorie.Id).Count();
I need to get the amount of visible pages which has a certain property value, eg. content picker with Id of the career category.
First of all, you should probably be using TypedContentAtRoot and not ContentAtRoot. TypedContent is retrieved from the Umbraco.config xml cache rather than the database so should be faster.
From your explanation I think you are saying that this line is the problem
var careerCategorieRep = contentRepository.Children.Where("DocumentTypeAlias == \"ucCareersCategoryRepository\"").FirstOrDefault();
Change it to
var contentRepository.Children.FirstOrDefault(n => n.DocumentTypeAlias == "ucCareersCategoryRepository");
That should do it.
Okay my other answer has some good advice but I think your problem may be something else.
if you are searching for Visible nodes this relies on a property on your document type called umbracoNaviHide. The property should be of a true/false datatype.
You have to add this property to the doc type and then set it to true (checked) if you wish to hide a node.
Then you can use either
myNode.Children.Where("Visible")
OR (just to show the way in which you can write lambda filter expressions)
myNode.Children.Where(x => x.IsVisible())
OR (this last just to illustrate that umbracoNaviHide is just a property on a doc type)
myNode.Children.Where(x => x.GetPropertyValue<string>("umbracoNaviHide")=="1")
Ok I have found the solution:
I needed to surround the Id with quotes because its stored as a string and not as a int.
var count = careersList.Children.Where("Visible && function == \"" + careerCategorie.Id + "\"").Count();

XPath Node selection

I am using HtmlAgilityPack to parse data for a Windows Phone 8 app. I have managed four nodes but I am having difficulties on the final one.
Game newGame = new Game();
newGame.Title = div.SelectSingleNode(".//section//h3").InnerText.Trim();
newGame.Cover = div.SelectSingleNode(".//section//img").Attributes["src"].Value;
newGame.Summary = div.SelectSingleNode(".//section//p").InnerText.Trim();
newGame.StoreLink = div.SelectSingleNode(".//img[#class= 'Store']").Attributes["src"].Value;
newGame.Logo = div.SelectSingleNode(".//div[#class= 'text-col'").FirstChild.Attributes["src"].Value;
That last piece of code is the one I am having problems with. The HTML on the website looks like this (simplified with the data I need)
<div id= "ContentBlockList" class="tier ">
<section>
<div class="left-side"><img src="newGame.Cover"></div>
<div class="text-col">
<img src="newGame.Logo http://url.png" />
<h3>newGame.Title</h3>
<p>new.Game.Summary</p>
<img src="newGame.StoreLink" class="Store" />
</div>
</div>
</section>
As you can see, I need to parse two images from this block of HTML. This code seems to take the first img src and uses it correctly for the game cover...
newGame.Cover = div.SelectSingleNode(".//section//img").Attributes["src"].Value;
However, I'm not sure how to get the second img src to retrieve the store Logo. Any ideas?
newGame.Cover = div.SelectSingleNode(".//img[2]").Attributes["src"].Value;
You didn't post the entire thing but, this should do the trick.
You can try this way :
newGame.Cover = div.SelectSingleNode("(.//img)[2]")
.GetAttributeValue("src", "");
GetAttributeValue() is preferable over Attributes["..."].Value because, while the latter throws exception, the former approach returns the 2nd parameter (empty string in the example above) when the attribute is not found.
Side note : your HTML markup is invalid as posted (some elements are not closed, <section> for example). That may cause confusion.

Icons for each file type

In my MVC application, user can upload various type of files (pdf, jpg, txt etc) and I want to show icon specific to each type, currently I am using one icon (pdf) for the purpose, I want, that based on the file type, associated icon should be displayed. Please guide me what kind of approach I can use for this purpose
<td>
#if (item.CalibratedBy != null){
<a href = #Url.Action("ViewCertificate", new { fileName = item.CalibrationCert }) >
<img src = "#Url.Content("~/Content/Icons/pdf.jpg")" alt = "attachment" /> </a>
}
</td>
Expose the extension type needed as a property on item (presumably being passed in through the Model)
Create an HtmlHelper extension method that will take in item.FileType and return the path to the appropriate icon file to be used. Call this in your <img> tag.

Resources