i'm developing application using Grails 2.5.1 i have a weird behaviors in the web browsers ( Chrome 59.0.3071.115 and Internet explorer 11 ) , what i'm doing is setting a session variable in the GSP and checking it in the controller.
In the GSP i'm setting the session variable isHR to true if the user clicked id=HR link
Here is my GSP:
<body>
<script>
$("#HR").on('click', function() {
alert ("hiii")
$(document).html("<g:set value="true" var="isHR" scope="session"/>");
});
</script>
<li ><g:link controller="login" action="auth" elementId='login'>
<g:message code='spring.security.ui.login.login' />
<span class="glyphicon glyphicon-log-in"></span>
</g:link></li>
<li>
<g:link elementId='HR' controller="login" action="auth" >
<g:message code='employmentSeeker.login.link' />
<span class="glyphicon glyphicon-log-in"></span>
</g:link></li>
</body>
here is the controller where i check on the isHR session variable :
def create() {
log.info ("Creating new User")
println "checking session " +session.isHR
respond new Users(params)
}
the output while using Chrome after pressing link with id=login or id=HR :
checking session null
the output while using Internet explorer after pressing link with id=login :
checking session true
How come this could happen !!
Thanks
This doesn't work that way. If you want to set some session-scoped variable from a GSP, you have to call a controller action either per normal request or AJAX, where the variable will be set. Thus it will also be browser-agnostic.
Related
We have this AngularJS SP application (smart-mirror) in electron browser, which has user createable extensions.
the extensions are small snippets of html that use angular directives
and use controllers and services.
to install an extension, one has to edit the main page and insert the script tags for the controller and service functions and a <div ng-include= ...> for the snippet of HTML
hardcoded this single page app works great.
but I want to add the capability to this app (opensource) to dynamically load those elements somehow...
adding the tags to the dom works, BUT are not processed correctly.
the HTML is processed before the scripts (from the inserted tags) are run, and when the ng-include inserts the HTML snippet, then controllers are not defined yet...
the body (with the extensions in hard-coded positions commented out)
<body ng-controller="MirrorCtrl" ng-cloak>
<div class="top">
<div class="top-left">
<!-- <div ng-include="'plugins/datetime/index.html'"></div>
<div ng-include="'plugins/calendar/index.html'"></div> -->
</div>
<div class="top-right">
<!-- <div ng-include="'plugins/weather/index.html'"></div>
<div ng-include="'plugins/traffic/index.html'"></div>
<div ng-include="'plugins/stock/index.html'"></div>
<div ng-include="'plugins/tvshows/index.html'"></div>
<div ng-include="'plugins/ha-display/index.html'"></div> -->
</div>
</div>
...
...
<script src="filename.service"/>
<script src= filename.controller"/>
</body>
the calendar extension html (inserted into specific div area of the page)
<ul ng-controller="Calendar" class="calendar fade" ng-show="focus == 'default'" ng-class="config.calendar.showCalendarNames ? 'show-calendar-names' : ''">
<li class="event" ng-repeat="event in calendar" ng-class="(calendar[$index - 1].label != event.label) ? 'day-marker' : ''">
<div class="event-details">
<span class="day">
<span ng-bind="event.startName"></span>
<span ng-if="event.startName != event.endName"> - <span ng-bind="event.endName"></span></span>
</span>
<div class="details calendar-name" ng-bind="event.calendarName"></div>
<span class="summary" ng-bind="event.SUMMARY"></span>
<div class="details" ng-if="event.start.format('LT') != event.end.format('LT')">
<span ng-if="event.startName != event.endName"><span ng-bind="event.start.format('M/D')"></span> <span ng-bind="event.start.format('LT')"></span> - <span ng-bind="event.end.format('M/D')"></span> <span ng-bind="event.end.format('LT')"></span></span>
<span ng-if="event.startName == event.endName"><span ng-bind="event.start.format('LT')"></span> - <span ng-bind="event.end.format('LT')"></span></span>
</div>
<div class="details" ng-if="event.start.format('LT') == event.end.format('LT')">All day</div>
</div>
</li>
</ul>
the calendar extension controller (used by the html)
function Calendar($scope, $http, $interval, CalendarService) {
var getCalendar = function(){
CalendarService.getCalendarEvents().then(function () {
$scope.calendar = CalendarService.getFutureEvents();
}, function (error) {
console.log(error);
});
}
getCalendar();
$interval(getCalendar, config.calendar.refreshInterval * 60000 || 1800000)
}
console.log("registering calendar controller")
angular.module('SmartMirror')
.controller('Calendar', Calendar);
the calendar extension service (used by the controller, shortened for this discussion)
(function () {
'use strict';
function CalendarService($window, $http, $q) {
...
...
return service;
}
console.log("registering calendar service")
angular.module('SmartMirror')
.factory('CalendarService', CalendarService);
} ());
so a user wanting to add an extension would have to create these files,
and edit the main page HTML and insert them
<div ng-include src="filename.html"></div>
in the right place and then add the
<script src="filename.service" >
and
<script src="filename.controller">
in the right place and order, service needs to be done before the controller,
as controller uses service.
anyhow, it's easy to add code to locate all the extensions and dynamically insert elements into the dom in their respective places... but...
in the hard coded, the scripts are added after the html in the body
so, I added a new script (processed when the page is loaded), which locates and inserts all the elements to support the extensions in the right places..
and then the script ends.... (last one in the hard-coded HTML) and the HTML directives are processed and boom, the dynamically added scripts have not been loaded or processed, so the controllers are not found...
I CAN create a temp HTML file with all this info in it and load THAT instead of dealing with the dynamic loading, but I think its better to resolve this
I have tried creating my own angular directive and compiling that in, but get stuck in a loop
<divinc src="filename.service"></divinc>
the inserted div is correct, as a child of the divinc directive
angular.module('SmartMirror')
.directive("divincl", ["$compile" ,function($compile){
return {
priority: 100,
terminal: true,
compile: function(scope, element, attrs) {
var html = "<div ng-include=\"" + element['incl']+ "\" onload='function(){console.log(\'html loaded\')}'></div>"
var templateGoesHere = angular.element(document.getElementById(element['id']));
templateGoesHere.html(html);
//document.body.innerHTML='';
var v= $compile(templateGoesHere);
//scope.$apply();
return function linkFn(scope) {
v(scope) // Link compiled element to scope
}
}
}
}]);
advice on how to solve this problem.. Thanks
In order to make an angularjs 1.7 application load dynamically extensions, there are 2 ways:
either use "nested angularjs applications", which is clearly an advanced use of angularjs and will require you to communicate between 2 angularjs applications, to use $scope.$apply to tell the other app to update etc..
either don't load them dynamically in the frontend, but in your backend when generating the html page which contains the application. Try to list all the extensions from the start.
I recommend you to forget the use of ng-include too, and the fact of trying to add <script></script> inside a directive of your application.
First, you need to re-understand how an angularjs application is started.
When you load your main application, you have a script in which angular.module, angular.directive, angular.value, angular.config, angular.run ... calls are made. This is the declaration step
If you declare a module MyApp and that in your html you have a DOM element with ng-app="MyApp", angularjs will automatically run angular.bootstrap() on this DOM element in order to start MyApp. The execution of the application starts here. You cannot declare anything anymore in the module MyApp.
Secondly, I think that <script></script> code inside templates is sanitized and removed by angular. Plus, even if you execute the code, since the declaration step has finished, you are not supposed to create new directives or register new services, it won't work.
A good way is that when you load your plugin, you:
Load the script of the plugin from the start, it must declare a new module like MyPlugin1.
In the directive which will contain the plugin, put the code of the link I sent you, which makes possible to insert a sub-application. In the end you will have a <div ng-app="MyPlugin1"></div> inside your directive's template
Then call angular.bootstrap on that node, which will make possible to start the sub application.
If you do this, you can run the sub application, but you didn't pass it parameters. In order to pass it parameters, you can put the code of the module MyPlugin1 inside a function, in order to have an application factory. Then use app.value('param1', parameter1) to initialize the app.
For example:
function declarePlugin1(myParam1, myParam2) {
var app = angular.module('MyPlugin1', []);
// app.directive();
app.value('myParam1', myParam1);
app.value('myParam2', myParam2);
}
And inside the directive call declarePlugin1("test", 42);, which will declare the application MyPlugin1 with the initialized values, and then angular.bootstrap to tell angularjs to start this application.
You can pass callbacks too, in order to communicate between the 2 applications.
Im trying to create a link in a view of AngularJS application just to send a data-method DELETE.
My route:
app.delete('/logout', function(req, res) {
req.session = null
res.status(200)
res.redirect('/')
})
My PugJS template:
a(ng-href='/logout', data-method='delete', data-confirm='Are you sure?', rel='nofollow')
span(translate) Logout
The HTML generated:
<a ng-href="/logout" data-method="delete" data-confirm="Are you sure?" rel="nofollow" class="" href="/logout">
<span translate="translate" class="ng-scope">
<span class="ng-scope">Logout</span>
</span>
</a>
But when I follow the link I receive the follow message:
Cannot GET /logout
It's looks to me that the data-method isn`t working. Does some one know what is happening?
Thanks for while.
I suppose you are used to use data-method with Rails. In AngularJS (or HTML), there is no such thing as data-method.
My suggestion is to either write your own directive to send the delete, or to add an action in your controller and use ng-click instead.
I have two forms in a single page.One of them is for adding comment, the other one is the main blog content as follows.
My aim is to have blog page with adding comment functionality.When user adds a comment , I want to post the comment another controller using ajax.When providing this functionality,I want user stay at the same page and update comments partial view at the page.However I couldn't achieve this with the codes below.
Main Blog Content
#model WforViolation.Models.Violation
#{
ViewBag.Title = "Details";
}
<h1>#Model.Title</h1>
<p class="lead">
Posted by #Model.CreatorUser.UserName
</p>
<hr>
<!-- Date/Time -->
<p><span class="glyphicon glyphicon-time"></span> Posted on #Model.CreationDateTime <span class="glyphicon glyphicon-flag"></span> #Model.Severity Severity <span class="glyphicon glyphicon-comment"> </span> #Model.Comments.Count Comments </p>
<p><span class="glyphicon glyphicon-eye-open"> People Viewed</span></p>
<hr>
<!-- Preview Image -->
<img class="img-responsive" src="#Model.Picture.FirstOrDefault().MediumPath" alt="">
<hr>
<!-- Post Content -->
<p class="lead">#Model.Title</p>
<p>#Model.Description</p>
<hr>
<!-- Blog Comments -->
<!-- Comments Form -->
#Html.Partial("_AddComment", new WforViolation.Models.CommentViewModel() { ViolationId=Model.Id,Content=""})
<hr>
<!-- Posted Comments -->
<!-- Comment -->
#Html.Partial("_Comments",Model)
Add Comment View
#model WforViolation.Models.CommentViewModel
<div class="well">
<h4>Leave a Comment:</h4>
#using (Ajax.BeginForm("AddComment", "Comment", null, new AjaxOptions
{
HttpMethod = "POST",
OnSuccess = "SuccessMessage",
OnFailure = "FailMessage"
//UpdateTargetId = "resultTarget"
}, new { id = "MyNewNameId", role = "form" })) // set new Id name for Form
{
#Html.AntiForgeryToken()
<div class="form-group">
#Html.TextAreaFor(model => model.Content, new { #rows = 3 })
</div>
<button type="submit" class="btn btn-primary">Submit</button>
#Html.HiddenFor(model=>model.ViolationId)
}
</div>
<script>
//\\\\\\\ JS retrun message SucccessPost or FailPost
function SuccessMessage() {
alert("Succcess Post");
}
function FailMessage() {
alert("Fail Post");
}
</script>
My Comment Controller
[HttpPost]
public ActionResult AddComment(CommentViewModel commentViewModel)
{
Comment comment = new Comment();
var userID = User.Identity.GetUserId();
if (!string.IsNullOrEmpty(userID))
{
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
var currentUser = manager.FindById(User.Identity.GetUserId());
comment.ApplicationUser=currentUser;
}
var violationId = commentViewModel.ViolationId;
Violation violationCommentedOn = context.Violations.Where(x => x.Id == violationId).FirstOrDefault();
comment.Violation = violationCommentedOn;
context.Comments.Add(comment);
context.SaveChanges();
var result = Json(
new
{
Success = true,//success
StatusMessage = "Object created successfully"
});
return result;
}
When I added a comment it redirects me to another page called localhost/Comment/AddComment its content is just the Json.
Is it ever possible to just retrieve JsonResult and stay at the same page ?
Or I cant post a form data using ajax and not redirecting to another page?
I know there are similar questions but I couldn't find the exact answer.
Any help is appreciated.
You are using Form in your Add Comment view and that form calls AddComment in your controller that returns a json data. Forms do cause a redirect to the method they call and because your controller is returning json, the browser simply displays it on a new page.
You may either return a view from your AddComment method in the controller. This view could be the comment view. This way the control will redirect back to the same view with new data. This is a sample code, in practice, this code should be pretty much the same as you may have it in ShowAddCommentView method of the controller.
CommentViewModel commentVM;
/// populate commentVM from DB or comment store
/// remove return result;
return View("AddCommentView", commentVM); /// your add comment view name
Or instead of using Form to send data to the controller, use a simple ajax call without using AjaxForm. When a user clicks on the button, you can call Ajax in javascript. I have a jquery example. parameter1, parameter2 are the same as properties of your CommentViewModel. Of course, you can also use json data parameter in this call instead passing parameters like in this following sample.
$.ajax({
url: '/Comment/AddComment?parameter1='+ pvalue1 + '¶meter2=' + pvalue2,
async: false,
cache: false,
type: 'POST',
success: function (msg) {
/// this msg object is actually the json object your controller is returning.
}
});
This call will not cause the page to redirect. When json is returned, you may write code in javascript to do something with that data, perhaps display it back on the add comment page.
It is possible to make this ajax call from asp.net directly without using a separate javascript. But I can't seem to remember it exactly right now.
I have api for search functionality which has written in Laravel PHP.When I type some string in input tag and click on search button, then I am geeting the json response.
Now what I have to do is on ngClick a new html page should open say "search.html" with display the json response using angularjs.
I am not able to do, may be my lake of knowledge:). Can anybody tell me how can I do this.
Here is my code:
// Search Controller
QAApp.controller('SearchCtrl', function ($scope, $http) {
$scope.search = function (searchtag) {
var request = $http({
method: 'GET',
url: server + 'api/question/tagged/' + searchtag,
});
request.success(function(data, status, headers, config) {
console.log(data);
$scope.qa = data;
});
}
});
html page is :
<div class="collapse navbar-collapse navbar-ex1-collapse" ng-controller = "SearchCtrl">
<div style = "float: right; margin-top: 7px;" class="col-sm-3 col-md-3">
<form class="navbar-form" role="search">
<div class="input-group">
<input type="text" class="form-control" placeholder="Search...." name = "tag" ng-model = "tag">
<div class="input-group-btn">
<button type="submit" class="btn btn-primary" ng-click = "search(tag);">
<span class="glyphicon glyphicon-search"></span>
</button>
</div>
</div>
</form>
</div>
Over here you have two different pages and whenever you are moving from one page to other (no SPA) the page will complete refresh....so if one is thinking of having it in global variables, services or even $rootScope that will not work as these variables will get refreshed.
In order to cope up then we either need to work with cookies, querystring or the browser localStorage.
In order to use local Storage in Angularjs you need to include a script in both the pages for angular-local-storage Github Link
Code Example how to use it:
angular.module('yourModule', ['LocalStorageModule'])
.controller('yourCtrl', [
'$scope',
'localStorageService',
function($scope, localStorageService) {
// Start fresh
localStorageService.clearAll();
// Set a key
localStorageService.set('Favorite Sport','Ultimate Frisbee');
// Delete a key
localStorageService.delete('Favorite Sport');
}]);
/*
To set the prefix of your localStorage name, you can use the setPrefix method
available on the localStorageServiceProvider
*/
angular.module('yourModule', ['LocalStorageModule'])
.config(['localStorageServiceProvider', function(localStorageServiceProvider){
localStorageServiceProvider.setPrefix('newPrefix');
}]);
Library main functions:
.set : to set a key value in the localStorage space
.clearAll: clear all the keys in localStorage
.delete: delete a key
.get: get a key from localStorage
Working Fiddle
Reference of what local Storage is actually about
I am trying to write a web interface to start a recording or playback process. I am using web.py and have one controlling python script (code.py) and three templates (main.html, record.html and playback.html) in a templates directory. The main page shows a form for playback and a form for recording, each with a button, which loads the relevant template with entered data when pressed. I would like to be able to cancel these processes and return to the main screen, so I have a form containing a 'Cancel' button which is rendered in both the record and playback templates. However, when I press this button. nothing happens. Any ideas would be appreciated.
code.py:
import web
from web import form
import os
import glob
import socket
render = web.template.render('templates/',
globals={'os':os, 'glob':glob, 'form':form})
urls = ('/*', 'index')
recordForm = form.Form(
form.Dropdown(name = 'rmode',
description='Recording Mode:',
args=<a list of tupels>),
form.Button('Record'),
)
os.chdir("/home/stingray/Documents/")
playbackForm = form.Form(
form.Dropdown(name='pmode',
description='Playback Mode:',
args=<a list of tupels>),
form.Dropdown(name='pfile',
description='Playback File:',
args=[(file,file) for file in glob.glob("*.*")]),
form.Button('Playback'),
)
cancelForm = form.Form(
form.Button('Cancel'),
)
class index:
def GET(self):
r = recordForm()
p = playbackForm()
return render.main(socket.gethostbyname(socket.gethostname()),
'Not Present',r,p)
def POST(self):
formData = web.input()
c = cancelForm()
try:
return render.record(formData.rmode,c)
except AttributeError:
return render.playback(formData.pmode,formData.pfile,c)
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()
main.html
$def with (ipAddress,linkStatus,recordForm,playbackForm)
<html>
<title>
Test Bridge Control - Main
</title>
<body>
<center>
<b>Test Bridge Control</b><br><br>
<form method="POST">
$:recordForm.render()
</form>
<br>
<form method="POST">
$:playbackForm.render()
</form>
<br>
Test bridge IP address: $ipAddress<br>
Link status: $linkStatus<br>
</center>
</body>
</html>
record.html
$def with (mode,cancelForm)
<html>
<title>
Test Bridge Control - Record
</title>
<body>
<center>
Recording in mode $mode <br>
<form method="POST">
$:cancelForm.render()
</form>
</center>
</body>
</html>
And playback.html is very similar to record.html. Note that even though I'm not validating the form data, I can still access it - form entries appear in the rendered record.html and playback.html.
[EDIT] Should probably emphasize that searches for similar issues haven't been successful; no-one else seems to be trying to use multiple forms one after the other (or if they are, they're succeeding).
[EDIT] Doesn't appear to be a problem in Firefox 18 running in Fedora, originally seen in IE9 in Windows 7, which is probably what it will have to work in.
Turns out it was an IE problem. Apparently IE9 does not treat buttons as being of type "submit" unless explicitly stated. Bizarrely the buttons in main did work as submit then stopped. All are now working after adding type="submit" to the button's declaration.