can I dynamically set the ID and view name? - javascript

<core:mvc.XMLView id="{path:' AssignmentModel>/AssignmentType' ,formatter:'.getViewName'}"
viewName="{path:' AssignmentModel>/AssignmentType' ,formatter:'.getViewName'}"
height="100%" visible="true"/>
I want view to be loaded based on assignemnt type.
I tried to dynamically load the view from controller, based on type.
but that itsnt working as expected.

If you use a View in an XMLView it will be created once. Even if your binding was working it would be OneTime, meaning it is only resolved once, which is obviously not what you are looking for.
You either have to use Routing as qualiture already mentioned or load your content dynamically from your controller and manually insert it in your view hierarchy. You could still use a PropertyBinding to observe property changes like this:
var binding = new sap.ui.model.PropertyBinding("AssignmentModel", "/AssignmentType");
binding.attachChange(function() {
var sViewName = this.getViewName(this.getModel("AssignmentModel").getProperty("/AssignmentType");
var oView = sap.ui.xmlview({
id: sViewName
viewName: sViewName
});
// pack your view whereever you want, clean the old view before
this.getView().addContent(oView);
}, this)
You might need to use sap.ui.model.odata.ODataPropertyBinding depending on the model you are using.
Code above is untested but it 'should' work.
GL
Chris

Related

How to have JavaScript functions work across different HTML pages?

I am building a website with several HTML pages, and going to fill up info on different pages through an API. I have added onclick listeners to HTML elements like this:
// ASSIGNING ELEMENTS AS VARIABLES
const EPL = document.getElementById('epl');
const bundesliga = document.getElementById('bundesliga');
const laliga = document.getElementById('laliga');
// ONCLICKS
EPL.onclick = function() {
getStandings('2021');
location.replace('standings.html');
}
bundesliga.onclick = function() {
getStandings('2088');
location.replace('standings.html');
}
laliga.onclick = function() {
getStandings('2224');
location.replace('standings.html');
}
When one of these is clicked, I call a function (getStandings) with its unique argument to fetch some data from the API. I also want to move to another HTML page, for which I used location.replace.
I'm caught in a dilemma: if I use the same JS file for every HTML page, when I get to the new HTML page, I get errors as the new HTML page does not have every element:
main.js:41 Uncaught TypeError: Cannot set property 'onclick' of null
But if I use different JS files, maybe one JS file for each HTML file, I cannot carry forward the bits of information I need. How can I get to the new HTML page, with its own JS file, without stopping and losing everything in the function I'm in currently, under the JS file of the old page? For example, the argument '2021' or '2088' are to be passed into the getStandings() function which will populate the new HTML page with data from an API. If I jump to a new HTML page with a new JS file, this is lost.
Is there a better way to organise my files? 😐😐😐😐😐
You can set your event listeners on the condition that the elements are not null e.g.
const EPL = document.getElementById('epl');
const bundesliga = document.getElementById('bundesliga');
const laliga = document.getElementById('laliga');
if(EPL){
EPL.onclick = function() {
getStandings('2021');
location.replace('standings.html');
}
}
etc...
Solved! As amn said, I can add URL parameters to the end of the URL of the new HTML page, then get the variables from its own URL once I'm on the new HTML page.
I think I would rather use classes instead of IDs to define the listener, and maybe IDs for dedicated action.

Get reference to existing OpenSeadragon Viewer

I need to add an overlay to an existing OpenSeadragon viewer object which isn't created by my code, but elsewhere in the application.
I have got to a point where I know that the viewer has been created as I can access the various html elements that are created via jQuery. However I can't work out if there's any way to create a viewer from an existing reference.
I've tried using the id of the viewer div in:
var viewer = OpenSeadragon(id: "open-seadragon-viewer-id");
but this doesn't seem to work.
Is there any way to do this or can you only get the viewer within the code that initialised it?
Here's one crazy thought... you could monkey-patch some portion of OSD in order to grab the viewer...
var viewer;
var originalIsOpen = OpenSeadragon.Viewer.prototype.isOpen;
OpenSeadragon.Viewer.prototype.isOpen = function() {
// Now we know the viewer!
viewer = this;
// Reinstate the original, since we only need to run our version once
OpenSeadragon.Viewer.prototype.isOpen = originalIsOpen;
// Call the original
return originalIsOpen.call(this);
}
It's kind of tacky, but should work. Note this assumes there is only one viewer on the page... if there are more than one, the same principle could work but you would need to keep track of an array of viewers.
BTW, I'm using isOpen, because it's simple and it gets called every frame. Other functions could work as well.
EDIT: fixed code so we are using the prototype. I still haven't actually tested this code so there may still be bugs!
This solution does not directly answer the question, as it relies on your own code creating the OpenSeaDragon object. It is an implementation of #iangilman's mention of storing the viewer in a global variable. However others may find it useful. (Note that passing a global variable to a function requires a workaround - see Passing a global variable to a function)
The code demonstrates how to use the same OpenSeaDragon object to display different pictures.
var viewer3=null; //global variable
var newURL1='image/imageToDisplay1.png';
var newURL2='image/imageToDisplay2.png';
var elementID='myID';
//the loadScan function will display the picture using openSeaDragon and can be called as many times as you want.
loadScan("viewer3",newURL1,elementID);
loadScan("viewer3",newURL2,elementID);
//the actual function
function loadScan(theViewer,newURL,theID) {
//if object has already been created, then just change the image
if (window[theViewer]!=null) {
window[theViewer].open({
type: 'image',
url: newURL
});
} else {
//create a new OpenSeadragon object
window[theViewer] = OpenSeadragon({
prefixUrl: "/myapp/vendor/openseadragon/images/",
id: theID,
defaultZoomLevel: 1,
tileSources: {
url: newURL,
type: 'image'
}
});
}
}

I can't access my current element

This is an instance of Rappid Toolkit which uses jointJS for building visual tools as for web development. http://i.stack.imgur.com/6XSis.png
In this toolkit you can make a graph which can become a website.
My problem is the following one:
In every single element of this graph there is a box below it with:x,y,width,height,angle.
I want to change this information of this boxcontent and to display some info from this element but the code in which I have to add my snippet is the following(var Halo is the var for my element in the graph):
var halo = new joint.ui.Halo({
cellView: cellView,
boxContent: function(cellView) {
return"Here I want to display my box content info instead of x,y,width,height, angle";
}
}).render();
If I try to add my code inside it to access in JSON format my current element info my full code is:
var halo = new joint.ui.Halo({
cellView: cellView,
boxContent: function(cellView) {
// Drawing
var selectedObjectDataText = JSON.stringify(this.cellView.toJSON());
var selectedObjectDataJSON = JSON.parse(selectedObjectDataText);
return(selectedObjectDataJSON[0].wi_name);
}
}).render();
where wi_name is the name of my element but in the first line I can't access the specific element of my graph.
var selectedObjectDataText = JSON.stringify(this.cellView.toJSON());
Is there any global way to access my halo(my graph element) since this.cellView.toJSON() doesn't work?
I tried this.model.toJSON() this.cellView.model.toJSON() etc with no result
Note that JointJS links and elements are Backbone Models (linkView and elementView are Backbone Views).
To get the current value of an attribute use get() method.
boxContent: function(cellView) {
return cellView.model.get('wi_name');
}
Alternatively you can use prop(), that can return also nested properties of a model.
boxContent: function(cellView) {
return cellView.model.prop('wi_name');
}
It worked for var selectedObjectDataText = JSON.stringify(cellView.model.toJSON());
Thank you all for your support.

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

How do I load data for Dojo Dgrid Table using AJAX?

I am exploring using DGrid for my web application. I am trying to have a table similar to this.
The code for the example above is here.
The table uses a memory store as the source of its data - the summary field there is what shows up when we click and expand each row.
I want the details(i.e the text shown when we click a row) to be fetched from the server on clicking on the row instead of being statically loaded along with rest of the page.
How do I modify the above code to be able to do that?
(My requirement is that of an HTML table, each row expandable on clicking, where the data on each expansion is fetched from the server, using AJAX for instance. I am just exploring dgrid as an option, as I get sortable columns for free with dgrid. If there is a better option, please let me know)
EDIT: Basically I am looking for ideas for doing that and not expecting anyone to actually give me the code. Being rather unfamiliar with Dojo, I am not sure what would be the right approach
If your ajax call returns html, you could place a dijit/layout/ContentPane in your renderer, and set the url of the contents you want to fetch in the ContentPane's href property. Assuming that your initial data (the equivalent of the example's memory store) would have a property called "yourServiceCallHref" containing the url you want to lazy load, your could try this :
require(["dijit/layout/ContentPane", ...], function(ContentPane){
renderers = {
...,
table: function(obj, options){
var div = put("div.collapsed", Grid.prototype.renderRow.apply(this, arguments)),
cp = new ContentPane({
href : obj.yourServiceCallHref
}),
expando = put(div, "div.expando", cp.domNode);
cp.startup();
return div;
}
});
If your service returns json, you could probably do something with dojo/request in a similar fashion. Just add your dom creation steps in your request callback and put them inside the div called "expando"...
Another option would be to replace the Memory store by a JsonRest store, and have the server output the same json format than the one you see on the Memory store. That means all the data would be fetched in a single call though...

Categories