How to pass data from controller javascript to view javascript in AngularJS? - javascript

I am developing an application in angularJS. I get data from a rest service in the controller. And then I pass that data to the view using $scope. In my view, there is an inpage javascript (I know its a bad practice) and I want to used the data passed in my inpage javascript. Simply using the variable name or {{variable_name}} doesnt work. Can any one give any suggestions?
Here is my code snipper from controller:
$scope.requests = null;
var url = 'my_url';
$http.get(url).then(function(response)
{
$scope.requests = response.data;
if (response.data.status && response.data.message)
{
var status = response.data.status + '!';
var message = response.data.message;
showAlert(status,message);
}
return;
}).catch(function(response)
{
showAlert('danger!','Some error occured. Please try again.');
});
And here is my inpage javascript code:
<script>
$(document).ready(function() {
/*
date store today date.
d store today date.
m store current month.
y store current year.
*/
var date = new Date();
var d = date.getDate();
var m = date.getMonth();
var y = date.getFullYear();
/*
Initialize fullCalendar and store into variable.
Why in variable?
Because doing so we can use it inside other function.
In order to modify its option later.
*/
$('#calendar').fullCalendar({
// put your options and callbacks here
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
defaultView: 'month',
/*
selectable:true will enable user to select datetime slot
selectHelper will add helpers for selectable.
*/
selectable: false,
selectHelper: false,
/*
editable: true allow user to edit events.
*/
editable: false,
/*
eventStartEditable: false doesnt allow the dragging of events
*/
eventStartEditable: false,
/*
eventOverlap: false doesnot allow overlapping of events
*/
eventOverlap: false,
/*
events is the main option for calendar.
for demo we have added predefined events in json object.
*/
/* var events = requests.map(function(obj, index)
{
if (obj.accepted == 'no' ) return false;
return { id : obj.id, start : obj.start, end : obj.end }
})*/
});
});
</script>
<div id='calendar'></div>
Using {{requests}} prints out the data but it CAN NOT be used within the <script> </script> tags. I want to use it with the script tags

In angular you want to include the $window service in your controller, then set a variable on the $window object. The script tag can then check for window.requestsVariable. You are going have to handle the asynchronous nature of the request though, since the request variable will be empty till the request returns.
Further, as andrew.butkus pointed out, you probably don't want to do this. The jquery code could be simplified if you moved it into the linking function of an angular directive for the calendar, IMO.

Declare a global variable as var gloable; outside the controller and inside the controller assign whatever value you want to the declared global variable and then later you can access it inside your Jquery onready function.

Related

How to to trigger page component events when loading template using Ajax on Oro Platform?

I'm currently facing an issue on Oro Platform v.4.1.10.
I have a specific form page where I'm performing an ajax reload on a specific field change.
The thing is that everything is working well except that the CSS and JS are not applied to my ajax section when reloaded.
When I first load the page, everything is OK :
When the section is reload using Ajax :
An OroDateTimeType field is used in the reloaded section, and according to my issue, the datepicker doesn't init on it.
Some details about the way my Ajax call is performed :
define(function (require) {
'use strict';
let SinisterAjaxRepairman,
BaseView = require('oroui/js/app/views/base/view');
SinisterAjaxRepairman = BaseView.extend({
autoRender: true,
/**
* Initializes SinisterAjaxRepairman component
*
* #param {Object} options
*/
initialize: function (options) {
// assign options to component object
this.$elem = options._sourceElement;
delete options._sourceElement;
SinisterAjaxRepairman.__super__.initialize.call(this, options);
this.options = options;
},
/**
* Renders the view - add event listeners here
*/
render: function () {
$(document).ready(function() {
let sectionTrigger = $('input.repair-section-trigger');
let sectionTargetWrapper = $('.repair-section-content');
sectionTrigger.on('click', function(e) {
$.ajax({
url: sectionTrigger.data('update-url'),
data: {
plannedRepair: sectionTrigger.is(':checked') ? 1 : 0,
id: sectionTrigger.data('sinister-id') ? sectionTrigger.data('sinister-id') : 0
},
success: function (html) {
if (!html) {
sectionTargetWrapper.html('').addClass('d-none');
return;
}
// Replace the current field and show
sectionTargetWrapper
.html(html)
.removeClass('d-none')
}
});
});
});
return SinisterAjaxRepairman.__super__.render.call(this);
},
/**
* Disposes the view - remove event listeners here
*/
dispose: function () {
if (this.disposed) {
// the view is already removed
return;
}
SinisterAjaxRepairman.__super__.dispose.call(this);
}
});
return SinisterAjaxRepairman;
});
The loaded template just contains the form row to update in the related section :
{{ form_row(form.repairman) }}
{{ form_row(form.reparationDate) }}
I think that my issue is related to the page load events used by Oro to trigger the page-component events and update their contents but I'm stuck at this point, I don't find how to trigger programmatically this update on my Ajax success code, in order to have the same rendering of the fields on an initial Page load and an Ajax reload of the section.
Thank you for your help 🙂
The final fix, that I found thanks to Andrey answer, was to update the JS file like this, with the addition of content:remove and content:changed events on ajax response (success section) :
success: function (html) {
if (!html) {
sectionTargetWrapper
.trigger('content:remove')
.html('')
.trigger('content:changed')
.addClass('d-none');
return;
}
// Replace the current field and show
sectionTargetWrapper
.trigger('content:remove')
.html(html)
.trigger('content:changed')
.removeClass('d-none')
}
Hope it could help ! 🙂

rerender on fullcalendar.io removeing all events

I am not sure how to approach fullcalender.io. As I will be refreshing the calender, I thought I would return the calendar object like this.
var calendar = function (eventsObj) {
console.log(eventsObj);
return new FullCalendar.Calendar(document.getElementById("calendar"), {
plugins: ['interaction', 'dayGrid', 'timeGrid'],
defaultView: 'dayGridMonth',
defaultDate: new Date().getDate(),
header: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay'
},
events: eventsObj
});
}
I did it this way because I need to refresh all my events inside a bootstrap modal.
When Modal is shown I recall this function.
$("#assignModal").on("shown.bs.modal", function () {
calendar(globalEvents).rerenderEvents();
Here globalEvents is an array with all the events.
I initially render the calendar like this
window.onload = function () {
calendar(globalEvents).render();
};
Issue is that the calendar renders but It does not have any events whereas if I just render the calendar, it keeps all the events. I checked on their docs, they have different features in different versions. Any ideas? please?
So basically according to the v4 guides.
calendar.getEventSources().forEach(function (item) {
item.remove();
});
calendar.addEventSource(globalEvents);
This is how you would have to remove the events and render new ones. Here globalEvents is just an array I use to keep track of my refreshed events.
you can do something like below just remove old events attach new events and rerenderevents
below is some APIS which will help you
//remove old data
$('#fullCalendar').fullCalendar('removeEvents');
//Getting new event json data
$("#fullCalendar").fullCalendar('addEventSource', response);
//Updating new events
$('#fullCalendar').fullCalendar('rerenderEvents');
//getting latest Events
$('#fullCalendar').fullCalendar( 'refetchEvents' );
//getting latest Resources
$('#fullCalendar').fullCalendar( 'refetchResources' );
here is working example

Full Calendar trigger ajax call before event renders on calendar

I'm a bit lost where is the proper place to make this with the Full Calendar documentation and need some fiddle to point me into the right way. When my calendar loads the events, before them show up on the calendar, I need to make a ajax call into a wordpress db which should return a date of a post. Each post is an event on the calendar. Depending on the response of the database, if the post date is in future time than the current time, then the calendar should show this event in an specific color, if it is past or current time it should be another different specific color.
So basically, before each event renders on the calendar I need to trigger an ajax call for each of them and evaluate the data returned to apply them the right color for past/current events and future events.
Someone experienced with Full Calendar could point me a fiddle with an example how is this done within the Full Calendar documentation?
This is the code I went so far. I am looking to stay in the loop with the calendar refetchEvents and be able to fetch with ajax in the background data from the posts of a WordPress website to use it on the next refetchEvents trigger and so on.
$(function () {
var date = new Date();
var d = date.getDate();
var m = date.getMonth();
var y = date.getFullYear();
var webData = null; //array() data
$('#calendar-holder').fullCalendar({
eventRender: function(event, element, webData) {
var dataHoje = new Date();
/*
Use webData data taken with ajax on eventAfterAllRender callback option
inside this conditional statements to draw on the event box
colors and text values depending on the status and date of the post returned.
*/
if (event.start < dataHoje && event.end > dataHoje) {
element.css('background-color', '#FFB347');
element.find('.fc-event-inner').append('<span class="fc-event-status">ON AIR</span>');
} else if (event.start < dataHoje && event.end < dataHoje) {
element.css('background-color', '#77DD77');
element.find('.fc-event-inner').append('<span class="fc-event-status">Published</span>');
} else if (event.start > dataHoje && event.end > dataHoje) {
element.css('background-color', '#AEC6CF');
element.find('.fc-event-inner').append('<span class="fc-event-status">Schedued</span>');
}
},
eventAfterAllRender: function () {
webData = '(AJAX CALL TO WEBSITE POSTS I THINK SHOULD GO HERE)';
console.log(webData);
},
eventColor: '#378006',
complete: function() {
},
defaultView: 'basicDay',
googleCalendarApiKey: 'AIzaSyCtEQZsFtsY41kJ1Av5FftgX9kdfkHKH',
events: {
googleCalendarId: 'mywebsite.com_l84tadr5fulc7j0628g3g6oj3k#group.calendar.google.com'
},
header: {
left: 'prev, next',
center: 'title',
right: 'basicDay, basicWeek, month, '
},
lazyFetching: true,
timeFormat: {
agenda: 'h:mmt', // 5:00 - 6:30
'': 'h:mmt' // 7p
},
weekNumbers: false,
lang: 'en',
eventSources: [
{
url: Routing.generate('fullcalendar_loader'),
type: 'POST',
data: {
},
error: function() {
}
}
]
});
});
var refreshRate;
function reloadTime() {
refreshRate = setTimeout(reloadPage, 5000);
}
function reloadPage() {
$("#calendar-holder").fullCalendar("refetchEvents");
reloadTime();
}
$( document ).ready(function() {
reloadTime();
});
Changing the color:
The way you did it works, but the easiest way is to do it in eventDataTransform. Like so:
eventDataTransform: function(eventData){
if(eventData.end.isBefore(moment())){
eventData.color = "black";
}else{
eventData.color = "green";
}
return eventData;
},
Color Demo
Check if event exists
You didn't mention exactly what to do if the database returns false, but I'll assume you don't want nonexistent events rendered.
Since the source for your events is google calendar, this is actually kind of tricky. Normally, you would use the custom events function and do two ajax calls in it (one for the events and one for checking if they are valid). But you can't do this with google cal events.
So instead we will use eventDataTransform and only display the events after we know they exist.
eventDataTransform: function(eventData){
eventData.display = false; //Don't display until we check the server
eventData._uid = idCounter++; //unique ID. Don't need this if they already have unique IDs
ajaxCall(eventData); //check the server (will retroactively update the event to be displayed)
if(eventData.start.isBefore(moment())){ /*...*/ } //colors
return eventData;
},
The top of your eventRender callback should look like:
eventRender: function(event,element){
if(!event.display){ //Render only if the event exists
return false; //return false to stop the event from rendering.
}
/*...your other render code if you have any*/
}
Define your ajaxCall function outside of fullcalendar:
var ajaxCall = function(eventData){
$.get( "ajax/test.html", function( data ) {
setEvent(eventData._uid,data); //data should be a boolean
});
};
var setEvent = function(id,exists){
var fcEvent = $('#calendar').fullCalendar("clientEvents",function(event){ //get the associated event object
if(event._uid === id){
return true;
}
})[0];
if(typeof fcEvent !== "object")$.error("Event id "+id+" doesn't exist!"); //Throw error if it doesn't exist
fcEvent.display = exists; // Store the server response in the event
$('#calendar-holder').fullCalendar("updateEvent",fcEvent); // Updates and re-renders the event
}
JSFiddle Demo (using fake ajax calls)
Some Explanation
Couple of things that might be useful to know:
The word render in fullcalendar refers to actually displaying the events. It's done whenever the view changes (more often than events are fetched from the DB)
Event sources only fetch events when they are needed. They are stored client-side as data that can be rendered as needed.
eventDataTransform is called once after an event source retrieves an event.
So if you put your ajax call in eventAfterAllRender, the ajax call would be done everytime FC decided to render the calendar resulting in more ajax calls that necessary. It also means you would get a delay every time you change the view. It's much better to do it earlier than render-time.

$.when(ajaxCall) Versus success

I have the following code inside my asp.net MVC view:-
$('body').on("click", "#transferserver,#transfersd,#transferfirewall,#transferrouter,#transferswitch", function () {
$("#showoptions").dialog({
title: "Assign Selected Records To New Rack",
width: 'auto', // overcomes width:'auto' and maxWidth bug
maxWidth: 600,
height: 'auto',
modal: true,
fluid: true, //new option
resizable: false
});
var ajaxCall = $.ajax({
url: '#Url.Content("~/Rack/ShowTransferSelectedDialog")',
data: {
rackfrom: "#Model.Rack.ITsysRackID",
assettype: $(this).attr('id')//get the id for the clciked link, so that the submit button will call the associted action method.
},
type: 'get',
success: function (html) {
$('#showoptions').html(html);
$("#showoptions").dialog("show"); //This could also be dialog("open") depending on the version of jquery ui.
}
});
$.when(ajaxCall)
.then(function (data) { showDialog(data); });
});
I have the following questions:
What are the differences between the $when(ajaxcall) and on success ?
In my above code if I remove the $.when(ajaxCall) the dialog box will still be displayed . so is there any need to have it?
Thanks
EDIT
But one benefit i find for using $.when(ajaxCall) is that i have defined a custom authorization attribute as follow:-
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class CheckUserPermissionsAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
var viewResult = new JsonResult();
viewResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
viewResult.Data = (new { IsSuccess = "Unauthorized", description = "Sorry, you do not have the required permission to perform this action." });
filterContext.Result = viewResult;
}
}
}
currently if the user clicks on the link to display the dialog box and he is not authorize to do so , he will receive a jAlert containing the unauthorized message as follow:-
![enter image description here][1]
but if i remove the $.when(ajaxCall), then the user will not receive the unauthorization message , and instead the dialog will be blank .. so can anyone advice ?
1) This is the definition of jQuery when
Provides a way to execute callback functions based on one or more objects, usually Deferred objects that represent asynchronous events.
It make no sense to use it for a single ajax call, you want to use it for 2 or more so you wait for them to finish before executing some code.
2) I don't know what showDialog does but your dialog already shows because in your success handler you have $("#showoptions").dialog("show");. Again, no need at all to use when here

JQuery can't find variable from separate javascript file

I am using the cakephp framework and I created 2 separate javascript files and placed them into my webroot/js folder. The first javascript file contains modal dialog variables that contain the settings for the dialog boxes. The second javascript file contains other click event handlers that post data to an action and then open up the dialog.
The problem I am having is that the second file calls a variable from the first file using
$variablename and I get an error saying varaibleName is not defined.
Some code is below to show you what I mean.
From the first file:
var $editSel = $("#editSel_dialog").dialog(
{
autoOpen: false,
height: 530,
width: 800,
resizable: true,
modal: true,
buttons:
{
"Cancel": function()
{
$(this).dialog("close");
}
}
});
From the second file:
$('.neweditSel_dialog').live('click', function()
{
$.ajaxSetup({ async: false });
var selected = [];
$("#[id*=LocalClocks]").each(function()
{
if(false != $(this).is(':checked'))
{
var string = $(this).attr('id').replace('LocalClocks', '');
string = string.substring(10);
selected.push(string);
}
});
if(0 === selected.length)
{
$selError.dialog('open');
$selError.text('No Local Clocks Were Selected')
}
else
{
$.post('/LocalClocks/editSelected', { "data[Session][selected]": selected }, function(data)
{
});
$editSel.load($(this).attr('href'), function ()
{
$editSel.dialog('open');
});
}
return false;
});
This was working when I was using jquery-1.4.2.min.js, but I am using jquery1.7 now.
I also ended up putting the first file with all the variables inside of $(document).ready(function(){}); I tried putting the second file inside of a document.ready() function but that made no difference.
Any help would be great.
Thanks
You are dealing with an issue in scope. In javascript:
function foo() {
var greet = "hi";
}
function bar() {
console.log(greet); // will throw error
}
However:
var greet;
function foo() {
greet = "hi";
}
function bar() {
console.log(greet); // will log "hi"
}
You must define your variable in a common parent of both functions that need to access it. Unfortunately, since you do not use any modeling convention or framework, that is the window object (why are global variables bad?).
So, you must define var $whateveryouneed before and outside of both $(document).readys.
Also, keep the declaration and definition seperate. Your definition instantiates a jQuery object, so you must encapsulate it inside a $(document).ready() (use $(function() {}) instead):
var $editSel;
$(function () {
$editSel = $("#editSel_dialog").dialog(
{
autoOpen: false,
height: 530,
width: 800,
resizable: true,
modal: true,
buttons:
{
"Cancel": function()
{
$(this).dialog("close");
}
}
});
});
I don't think you can guarantee the order in which handlers will be fired, which means that the document ready may be fired in different order than you expect. Is the variable you are trying to access in the second file a global variable? Try to think about your variables scope as I would have thought this is the issue.
You cannot guarantee that one file will be loaded before the other. And you cannot guarantee that document.ready in one file will fire before the other.
Therefore, I suggest you wrap your code in functions and call them in a single document.ready handler in the order you need.
For example:
function initVariables(){
window.$editSel = ... // your code from the first file here
}
function initHandlers(){
// your code from the second file here
}
And then:
$(document).ready(function() {
initVariables();
initHandlers();
});
You'll notice that I used the global window object to expose your variable. It would be even better if you used a common namespace for them.

Categories