retrieving gravatar using jquery knockout js - javascript

I am trying to get the gravatar of multiple uses to be displayed in one page and i am using a foreach loop for that. Also i am using knockout js to get the information like email and name and returned as json. Since i cannot use razor with gravatar because it requests a string to be passed in as an email and what i have are returned "data-bind="text:Email"
I am trying to use the MD5 concept and i am very new to this and not sure if i am following the right steps. I found this online from google code: http://www.devcurry.com/2012/06/retrieving-gravatar-using-jquery.html
and i tried to implement but not sure if my code is properly written:
Part of my javascript related to what i am doing:
$.views.Games.UserViewModel = function (data) {
var self = this;
self.Name = ko.observable(data.Name);
self.Email = ko.observable(data.Email);
self.Hash = CryptoJS.MD5(Email);
};
My View Page:
<img alt="Gravatar" title="My Gravatar" data-bind="attr:{href:'http://www.gravatar.com/avatar/' +Hash()+'?s=30&d=identicon&r=G'}" />
With this i am not getting a gravatar to show. Any helpful information or tips is greatly appreciated.
Code update
I altered so this is how it looks:
view model
public string MD5Email { get{ return Email.MD5Hash(); } }
javascript
self.MD5Email = ko.observable('http://www.gravatar.com/avatar/' + data.MD5Email + '?s=30&d=identicon&r=G');
view page
<img width="158" height="158" alt="Gravatar" data-bind="attr:{'src':MD5Email()}"/>

First, don't put JS logic in your data-binds. Use a computed instead:
self.GravatarUrl = computed(function() {
return 'http://www.gravatar.com/avatar/' + self.Hash() + 's=30&d=identicon&r=G';
});
Second, your Hash needs to be a computed observable as well. The way you have it now, it's only evaluated once, when the JS first runs, and when most likely Email is null. So your Gravatar URL is never being populated with a valid email hash.
self.Hash = computed(function() {
return CryptoJS.MD5(self.Email);
});
However, since this Hash computed is only being used to serve the other computed at this point, you can and should probably just combine the two:
self.GravatarUrl = computed(function() {
var hash = CryptoJS.MD5(self.Email);
return 'http://www.gravatar.com/avatar/' + hash + 's=30&d=identicon&r=G';
});
Then, your data-bind becomes simply:
<img alt="Gravatar" title="My Gravatar" data-bind="attr:{ href: GravatarUrl }" />
Much cleaner.
UPDATE based on OP's update
I'm not sure why you changed the logic of the code I gave you, but that's why it's not working.
First, it seems you've given up on MD5 in Javascript and added it to your view model. That's fine, but you've introduced the same logic problem you had earlier by setting the self.MD5Email to the entire URL based on data.Email. This is not a computed and data.Email is not an observable. It exists only at the initial creation of the KO view model. What you should be doing is something like:
self.MD5Email = ko.observable(data.MD5Email);
self.Gravatar = ko.computed(function () {
return 'http://www.gravatar.com/avatar/' + self.MD5Email() + '?s=30&d=identicon&r=G'
});
You've rightly corrected setting the img src instead of href (I missed that too), but using the parenthesis is unnecessary when you're not doing other JS logic at the same time, so it should just be:
data-bind="attr: { src: Gravatar }"

Not sure if this helps but I wrote a binding to do just this recently:
https://github.com/grofit/knockout.gravatar
So you can just use it using the knockout binding goodness.

Related

What is the best practice for maintain a menu after a page reload? I have this custom code which feels wrong

I have a custom Menu which loads a new MVC View for each click as I want.
I load the new View by setting window.location.href. To make it work I have to set the baseURL (the name of the website) each time. To Store the state of the menu I use URL's querystring.
My concerns is in the use of:
'/WebConsole53/' // hardcode baseurl i have to apply each time manually
Setting window.location.href to load the new View from JavaScript // Is this the best way or should I use some URL/Html helpers instead?
I store the state of the selected menuItem in the querystring ("menu") // Is it more common to store that kind in Session/Cookie?
Any thoughts, corrections and suggestions would be much appriciated - thanks.
_Layout.cshtml
var controller = $self.data('webconsole-controller');
var action = $self.data('webconsole-action');
var menu = "?menu=" + $self.attr('id');
var relUrl = controller + "/" + action + menu;
var url = urlHelper.getUrl(relUrl);
window.location.href = url;
UrlHelper.js
var urlHelper = function () {
var getBaseUrl = '/WebConsole53/',
buildUrl = function(relUrl) {
return getBaseUrl + relUrl;
};
var getUrl = function(relUrl) { // relUrl format: 'controller/action'
return buildUrl(relUrl);
};
return {
getUrl: getUrl
};
}();
I Use MVC 5.
You can save this problem using Route. Through the route you know exactly where you are located in you application.
_Layout.cshtml is definetely not the place to have this javascript. Maybe you are missing some MVC concepts, I would recommend you to read a bit more about routes and routelinks
I hope this helps you a bit: RouteLinks in MVC
'/WebConsole53/' // hardcode baseurl I have to apply each time manually
sometimes you need to access your root from javascript where you don't have access to server-side code (eg #Html). While refactoring may be the best option you can get around this by storing the baseurl once, using server-side code, eg in _layout.cshtml:
<head>
<script type="text/javascript">
var basePath = '#Url.Content("~")'; // includes trailing /
</script>
... load other scripts after the above ...
</head>
you can then reference this everywhere and it will always be valid even if you move the base / migrate to test/live.
Setting window.location.href to load the new View from JavaScript // Is this the best way or should I use some URL/Html helpers instead?
Depends on your requirements - you could use $.ajax (or shortcuts $.get or $.load) to load PartialViews into specific areas on your page. There's plenty of examples on SO for this and the jquery api help.
Or just use <a> anchors or #Html.ActionLink as already suggested. Without needing menu= (see next) you don't need to control all your links.
I store the state of the selected menuItem in the querystring ("menu") // Is it more common to store that kind in Session/Cookie?
If you change the page, then you could query the current url to find which menu item points to it and highlight that one (ie set the menu dynamically rather than store it).
This would also cover the case where you user enters the url directly without the menu= part ... or where your forget to add this... not that that would happen :)
Additional: You can specify which layout to use in your view by specifying the Layout at the top of the view, eg:
#{
Layout = "~/Views/Shared/AltLayout.cshtml";
}
(which is also one of the options when you right click Views and Add View in visual studio)
Without this, MVC uses a configuration-by-convention and looks at Views/_ViewStart.cshtml which specifies the default _layout.cshtml.
If you don't want a layout at all, then just return PartialView(); instead

xpages href computed in javascript

I have an <a> tag which I'm using to redirect the user to another xpage.
Its href property is:
<a target="_blank" href="http://serv/MyBase.nsf">
I use a simple view listing a doc. which contains the server and the name of the application.
So, I want to use some #DbLookup function in javascript to get into 2 var the above server and app name:
var server = #Unique(#DbColumn(#DbName(), "myVw", 1);
var name = #Unique(#DbColumn(#DbName(), "myVw", 2);
var concat = server+"/"+name;
return concat;
How can I compute the href property to return the concat variable?
Create a Link control xp:link and calculate the URL in attribute value:
<xp:this.value><![CDATA[#{javascript:var server .... }]]></xp:this.value>
Knut's approach is correct, but your code isn't :-). For every XPages load (or refresh) you do 4 #DbLookup. You can do a set of optimisations here:
Combine the result you want in the view itself, so you only need one lookup
Cache the value in the session (or application scope)
something like this (add nice error handling):
if (sessionScope.myHref) {
// Actually do nothing here
} else {
sessionScope.myHref = #Unique(#DbColumn(#DbName(), "myVw", 3);
}
return sessionScope.myHref;
The 3rd column would have the concatenation in the view already. That little snippet does a lookup only once per session. If it is the same for all users, use the applicationScope then it is even less.

CQ5 AEM: how to get a component by name within a dialog using javascript

I know this will probably a simple question, but I'm new to CQ5 and AEM in general.
I have a cq:Widget node which is a simple textfield.
<rowtitlevalue
jcr:primaryType="cq:Widget"
fieldLabel="Row Title Value"
name="./rowtitlevalue"
xtype="textfield"
disabled="true"/>
Now at the moment within my JavaScript, I'm currently accessing it via
var textfield = panel.findByType('textfield')[1];
which works fine (there's another textfield before this one, hence the 1 in the array.
MY QUESTION:
how do I look for this field using it's NAME attribute within my javascript.
Any help would be appreciated.
Also, I'm using this object to run the following:
if (show != undefined) {
textfield.enable();
textfield.show();
}
else if (show == undefined) {
textfield.disable();
textfield.hide();
}
The JavaScript is located within the Component Based ClientLibs.
And this is the Listener that I have under the checkbox that defines the value of SHOW within the javascript (which is working fine).
<listeners
jcr:primaryType="nt:unstructured"
loadcontent="function(field,rec,path){Ejst.toggleRowTitle(field);}"
selectionchanged="function(field,value){Ejst.toggleRowTitle(field);}"/>
Please let me know if you see any problems with this.
Appreciate it in advance
The CQ.Dialog API defines the getField( String name) method which returns a field with the given name. In case more than one field with the same name exists, it returns an array of those fields.
Thus finding parent of xtype dialog instead of panel as shown below would solve this.
Ejst.toggleRowTitle = function(checkbox) {
var dlg = checkbox.findParentByType('dialog');
var rowTitleField = dlg.getField('./rowtitlevalue');
// perform required operation on rowTitleField
}
i did something like that a few days ago and my solution was to make a js file on the same level of the component and with the same name of the component with the information that i need.
Something like this:
The file will be called rowtitlevalue.js and the content would be:
"use strict";
use(function() {
var data = {};
data.rowtitlevalueData = properties.get("rowtitlevalue");
//more properties if needed...
return {
data: data
}
});
then where i need to use it in javascript, i need the following tags:
<sly data-sly-use.data="rowtitlevalue.js">
<script type="text/javascript">
var myVariable = ${data.rowtitlevalueData};
</script>
</sly>

How do I reference the local variable when creating Url.Action call?

Backstory: To specify the correct route for a jqGrid that I show on my ASP.NET MVC 3 page, I do something like so:
$('#jqgFlavors').jqGrid({
url: '#Url.Action("FlavorData", "IceCream")',
etc...
and that will produce the correct route either when running locally out of Visual Studio (where things live at something like "http://localhost:90125/IceCream" or on the deployed site where things live at something like "http://thehostsite/mydeployedsitename/IceCream".
Great. Now the issue I'm having is that I use the onSelectRow in the grid to do a master/details thing based on the selected row's flavor id value. First, I tried doing this to just get the route correct:
onSelectRow: function(theRow){
$('#flavorDetails').load('#Url.Action("Details","IceCream", new {id = 42)})');
}
So that I can pass the value 42 in as the 'id' parameter in the Details action of the IceCream controller. And that works fine, but of course I don't want to hard code the value 42, rather pull the flavor id from the grid itself. So I have tried to reference the flavorID but can't seem to get the syntax correct:
onSelectRow: function(theRow){
var grid = jQuery('#jqgFlavors');
var flavorID = grid.jqGrid('getCell', theRow, 'FlavorID');
$('#flavorDetails').load('#Url.Action("Details","IceCream", new {id = flavorID)})');
}
I'm sure you get what I'm going for here - referencing the flavorID value I extract from the grid. But what I get is a compilation error:
The name 'flavorID' does not exist in the current context.
I suspect this is really simple. How do I reference correctly that variable?
You could use the second argument of the .load() method which allows you to pass additional parameters:
var flavorID = grid.jqGrid('getCell', theRow, 'FlavorID');
$('#flavorDetails').load('#Url.Action("Details", "IceCream")', { id: flavorID });
This might probably use the following url: /IceCream/Details?id=123 instead of what you might want /IceCream/Details/123 because javascript doesn't know anything about your routes but why care? It will still map correctly to the controller action:
public ActionResult Details(int id)
{
...
}
But if you are really anal about urls and insist on having the first type of url I've seen people doing the following:
var flavorID = grid.jqGrid('getCell', theRow, 'FlavorID');
var url = '#Url.Action("Details", "IceCream", new { id = "_TOREPLACE_" })';
url = url.replace('_TOREPLACE_', flavorID);
$('#flavorDetails').load(url);
Personally I wouldn't do it but providing it just for the record.

Variable not updating in script string, yet it updates

Very confused here.
I have a search box which reads a list of school names from my database. When I select a school, the id (from the db) gets put in a hidden textbox.
I also have a search box which reads a list of courses from my database. However, I made the query so that it only reads the courses from the selected school.
It does that, in theory.
I was planning to pass the school id, which I grab from the hidden box, to the search script which in turn passes it to my database query. However, the variable I put my school id in doesn't seem to be updating.. yet it does. Let me explain.
I come on the page. The school for my test account has id 1. The id number in my hidden box is indeed 1. I search for a school which I know has some courses assigned to it: the id number in the box changes to 3.
I have a JS variable called school_id which I declared outside of my $(document).ready. I assume that means it's global (that's what I got taught even though SO told me once it isn't really the correct way to do this. Still have to look into that). I wrote a function which updates this variable when the school search box loses focus:
$("#school").blur(function() {
school_id = $("#school_id").val();
});
A quick javascript:alert(school_id); in my browser bar also shows the updated variable: it is now 3 instead of 1.
Onto the search script part of my page (excerpt of the script):
script:"/profiel/search_richting?json=true&limit=6&id=" + school_id + "&"
As you can see, I pass the school_id variable to the script here. However, what seems to be happening is that it always passes '1', the default variable when the page loads. It simply ignores the updated variable. Does this string get parsed when the page loads? In other words, as soon as the page loads, does it actually say &id=1? That's the only idea I can come up with why it would always pass '1'.
Is there a way to make this variable update in my script string? Or what would be the best way to solve this? I'm probably missing out on something very simple here again, as usual. Thanks a lot.
EDIT
Updated per request. I added a function getTheString as was suggest and I use the value of this function to get the URL. Still doesn't work though, it still seems to be concatenating before I get a chance to update the var. HOWEVER, with this code, my ajax log says id:[object HTMLInputElement], instead of id:1. Not sure what that means.
<script type="text/javascript">
var school_id;
$(document).ready(function() {
$("#school").blur(function() {
school_id = $("#school_id").val();
});
// zoekfunctie
var scholen = {
script:"/profiel/search_school?json=true&limit=6&",
varname:"input",
json:true,
shownoresults:false,
maxresults:6,
callback: function (obj) { document.getElementById('school_id').value = obj.id; }
};
var as_json = new bsn.AutoSuggest('school', scholen);
var richtingen = {
script: getTheString(),
varname:"input",
json:true,
shownoresults:true,
maxresults:6
};
var as_json2 = new bsn.AutoSuggest('studierichting', richtingen);
});
function getTheString() {
return "/profiel/search_richting?json=true&limit=6&id=" + school_id + "&";
}
</script>
This is because the URL is static, it is not updated as the ID changes.
You should update the URL as part of the code you wrote to get the ID:
$("#school").blur(function() {
school_id = $("#school_id").val();
// update URL here ...
});
Aren't you concatenating script:"/profiel/search_richting?json=true&limit=6&id=" + school_id + "&" before the event is fired and the var updated?
Okay. So the problem was my third party plug-in instead of the code I wrote. I fixed this by editing the code of the autoSuggest plugin so it now includes my id field in the AJAX request.
var url = this.oP.script+this.oP.varname+"="+encodeURIComponent(this.sInp)+"&id="+ $("#school_id").val();
Thanks to everyone who tried to help me out!

Categories