I'm working on an Angular project that makes use of a variable called WEB_HOST. I can see in another file where the variable is defined (it's somehow defined in a class called ProjectConfig).
Definition (simplified):
export class ProjectConfig {
WEB_HOST = 'https://example.com'; // I didn't think properties could be assigned here?
constructor() { ... }
}
Now, from a completely separate *.ts file, this obviously doesn't work:
let x = WEB_HOST; // x is undefined
However, in the same file, some existing code manages to access the variable's value by using a bizarre string interpolation:
let x = `<%= WEB_HOST %>`; // x == 'https://example.com'
What is going on here? I've never seen this <%= syntax before. Is it part of Angular? Typescript? I haven't been able to find any documentation on what it does.
I also don't know how it manages to get a property out of ProjectConfig (and I'm not sure it's a class property either... the definition being outside of any class function confuses me too).
So, this is ASP Tags.
If you take a look at the following from w3schools. https://www.w3schools.com/asp/showasp.asp?filename=demo_syntax_tags
You will see that it is used in the HTML for templating. It can also be used I believe in other files as it is processed on the server before the client application runs on your browser.
HTH
Looks like ERB, a Ruby templating engine that Ruby on Rails uses.
https://codingbee.net/tutorials/ruby/ruby-the-erb-templating-system
Others have mentioned that various languages use <%= some_code_here %> for templating.
Regardless of what language is processing it, I imagine your .ts file runs through some server side framework, that will put some string value in place of WEB_HOST, and then the .ts file will be transpiled to JS.
You could try this way on HTML file
{{window.location.origin}}
if it doesn't recognize the window variable we might need this in ts file
declare const window;
Related
I have one tricky question.
Is there a way to take C# const and use it in .JS script with Jquery ?
This is how const look:
public class UserRoles
{
public const string Read = "Read";
public const string ReadWrite = "ReadWrite";
}
It depends a bit of what you are trying to do with those values.
You could place the values in a js object when your UI initializes (ex: window.YourAppName.Constants.Read = "your C# constant" in Index.html). Then you could load your jquery script and make use of the constant values once the document finished loading.
Alternatively, if you are using MVC, you can make use of tags within your views, and thus have access to C# code (viewmodel, enums, etc.). However, if you have lots of js code then it would be best to keep that in js files and in such a case I would go for the first option.
You can't use Razor in JavaScript files, you would have to have the variable passed to a razor view in the viewbag/data or model.
Then in the shared layout you could create a javascript function that returns this variable, then in your .JS file you could call that function to get the variable as long as it is loaded after.
I have a javascript file abc.js. I have kept it inside app/assets/javascripts/abc folder.
In my application.js file, I have given
//= require abc/abc
In my view, I need to display the object that is returned by a function inside the abc.js file.
I am calling the function by the following command
%h4.sub-header Test Project
%textarea.form-control{rows: 10}
:javascript
abc.diff(#a, #b)
I am getting the a & b values from the controller.
But the function is not being called. Instead the sentence "abc.diff(a,b)" is being displayed.
Could anyone tell me how to call the function inside my view?
Inside haml javascript blocks you can just do string interpolation. Also indentation is very important in haml (obviously). So your view should look like:
%h4.sub-header Test Project
%textarea.form-control{rows: 10}
:javascript
abc.diff(#{#a}, #{#b});
Without more info it is hard to say more, but in general this is not the preferred way: your code should be precompiled in javascript assets, and generally I define variable or add data attributes to specific items.
So either something like
:javascript
var a = #{#a};
var b = #{#b};
ad inside abs.js.coffee write
$ ->
abc.diff(a,b)
The cleanest solution imho is something like:
%body{'data-a': #a, 'data-b': #b}
and inside abs.js.coffee write
$ ->
a = $('body').data('a')
b = $('body'_.data('b')
abs.diff(a,b)
Of course, this depends whether it applies to your solution, my apologies for digressing :)
Okay, so I am way new to Grunt and Node.js. I am building a site, and decided that the 'main.js' file was getting way too big. So, I split it up, and I am now trying to use Grunt to piece all of these JS files back together.
The issue that I have is that I need to make some global variables available to all of the various functions in all of these JS files. To be more specific, every page on our site is identified via an id in the body tag:
<body id="home">
Many of these JS files contain if statements that ensure certain functions only run if the appropriate page is loaded. For example:
if (page == 'home') {
var title = "Home Page"
$('.page-title').text(title);
}
Notice the page variable? That guy is the one that I need to make available to all of these files (after grunt-contrib-uglify merges them together). So, I figured I'd assign a new "unique" variable name, and make it global.
I noticed that grunt-contrib-uglify has a 'wrap' option listed in its documentation. However, no examples are given as to how to use it.
Can anyone tell me:
- How to use the 'wrap' option in 'grunt-contrib-uglify'
- If this is the right grunt plugin for what I am trying to do?
One idea I had (as a last resort) is to create a before.js and after.js and put the beginning and end (respectively) of what I wish to wrap around the other files in each. But, I think the 'wrap' option is what I need, yes?
UPDATE: Here is a link to my "merged" JS file:
main.js
And a link to my Gruntfile:
Gruntfile.js
I have been having the same problem an searching for a solution. But I think I found an answer.
Use this in your gruntfile:
uglify: {
options: {
wrap: true
}
}
The documentation for the wrap property indicates that the variables will be made available in a global variable, and looking at the generated code that does seem to to be the case. Passing a string value to the parameter does seem to create a global variable with that name.
However, wrap: true seems to make all objects and properties available in the global scope. So instead of globals.page.title (which I can't get to work, anyway), you can just use page.title. Much, much easier and simpler.
If this suits your purposes, I'd recommend doing this instead.
Ok this one is tricky, I have been stucked for a while...
Way you do this with grunt-contrib-uglify for frontend JS
create multiple files like
SomeClass.js
OtherClass.js
main.js
and use some module (grunt-file-dependencies or grunt-contrib-concat) and setup it to concat your files. Then setup uglify in your Gruntfile.js like
...
uglify: {
options: {
wrap: "myPublicObject",
...
},
In file (main.js for example) exports variable has to be assigned, the entire file might look like this:
var otherClassInst = new OtherClass();
var someClassInst = new SomeClass();
exports = otherClassInst;
Now what it exactly does
Uglify will pick superior context (this) and define property on it named myPublicObject. Then it wrap your sourcecode with function and create exports variable here (DO NOT DECLARE var exports anywhere). At the end it will assign what you exported to that property. If you dont assign anything (you dont use exports =) inital value is {}, so the property with void object exists anyway.
To make this super-clear,
if you put your code into page like <script src="myminifiedfile.min.js"></script>, then superior context is window =>
window.myPublicObject is instance of OtherClass while window.someClassInst, window.SomeClass and window.OtherClass are undefined.
this is unlikely, but if you just copy content of minified result and wrap it with different function, object you exported will be visible only via this["myPublicObject"] => uglify wrap doesn't make things globaly accessible, it makes them accessible in superior context.
I need to know if this is correct. I'm just beginning in app development using WinJS. I've identified the source of the problem and got rid of it but I don't know if that's the correct method.Please help!
// Optimize the load of the application and while the splash screen is
// shown, execute high priority scheduled work.
ui.disableAnimations();
var p = ui.processAll().then(function () {
//return nav.navigate(nav.location || Application.navigator.home, nav.state);
return nav.navigate(nav.location || app.local, nav.state)
}).then(function () {
return sched.requestDrain(sched.Priority.aboveNormal + 1);
}).then(function () {
ui.enableAnimations();
});
The problem is in the first .then(). The commented line was the default line, I've changed it for the app to work.I've absolutely no idea what it is.Please tell me what it means and what is changed. By the way, 'app' is WinJS.Application and Application is a WinJS namespace in navigator.js where the home property is located.
This error would suggest that navigator.js isn't being loaded by the time this code is executed. The Application namespace, which is entirely arbitrary and unrelated to WinJS.Application, is defined only in navigator.js, so if that file isn't loaded that namespace won't exist.
A WinJS namespace, by the way, is just a formalization of a module pattern in JavaScript that helps you keep the global namespace from getting cluttered. Declaring a namespace like navigator.js does it:
WinJS.Namespace.define("Application", {
PageControlNavigator: WinJS.Class.define(
just creates a single object in the global namespace called "Application" and then defines members for it. (You can change "Application" to anything you want, by the way. Nothing else in navigator.js relies on it, and navigator.js is something that comes from the app templates in Visual Studio and isn't part of WinJS itself.)
So again, my suspicion is that you don't have (or whatever the proper path is) in your default.html, the path to it isn't correct, or that perhaps it's being loaded after the other code is trying to execute. Try setting breakpoints on WinJS.Namespace.define and see if that file is loaded and the breakpoint gets hit.
Can anyone explain how i can access the rails routes/names routes in javascript ?
The following are some of the things i tried
http://github.com/jsierles/js_named_routes.
but no luck.
I was researching this question for a while and didn't found any implementation compatible with Rails 3.
So decided to write my own:
https://github.com/railsware/js-routes
kishore I think this is the simpliest way, just call:
Rails.application.routes.url_helpers.*_path
So, if you have in your routes.rb, let's say:
resources :users
then you want to call the index action from a javascript file, you do:
$.get('<%= Rails.application.routes.url_helpers.users_path %>', function(data){ ...
Take into account that the js file should have a .erb extension (or *.js.erb) so rails knows that must be preprocessed. Otherwise, the file will be served as is.
If I understand your requirement correctly you want Javascript code in your views to have access to the named routes. If so, then one simple way to do this is to render your Javascript code through a template (ERB, Haml, etc) and then to expand the routes something like the following:
ERB:
<script>
$.get('<%= some_named_route_path %>', function(data) {
});
</script>
Haml:
:javascript
$.get('#{ some_named_route_path }', function(data) {
});
UPDATE: Adding suggestions for public/javascripts/ case
Accessing named routes from the public folder is a bit trickier but there at least 2 ways that come to mind, neither of which is entirely satisfactory but, one or either of which might suit your application
Create javascript templates in (say) lib/javascripts using ERB named like '*.js.erb' and a rake task to expand those templates into public/javascripts before deploying (say as a step in your Capistrano recipe for example). Downside of that is that your changes are not made available live on the site until the templates are expanded and you might not get the right syntax highlighting of your javascript with an .erb extension file
Create per-view javascript helper functions in a content_for :head block which expand the named routes and make those available to code from your public javascript files. If you're careful with namespacing and conventions this might work out well. The downside is that the code calling these javascript helpers is decoupled from the code that defines them which could be confusing for maintainers or prone to abuse.
In some view:
<% content_for :head do %>
<script>
SomeNameSpace.helper_to_some_named_route = function() {
return '%<= some_named_route_path %>
};
</script>
<% end %>
Then in public/application.js (say)
$.get(SomeNameSpace.helper_to_some_named_route(), function(data) {
});
bjg really answered this, but I thought I'd extract the relevant part and amplify with an example.
You simply provide your view a string variable whose value is a named Rails path, and then use that value in the Javascript of your form. An example that illustrates how a controller method can specify the path for another method, to be opened by the script on the press of a button:
File config/routes.rb:
...
resource :foo, :only => [:show, :reset]
...
match 'foo_reset_path' => 'foo#reset'
Commanding rake routes will now produce, among other output, this:
foo GET /foo(.:format) foo#show
foo_reset_path /foo_reset_path(.:format) foo#reset
foo_reset_path is what we're going to use here, but you can of course use this method with any named Rails path.
File app/controllers/foo_controller.rb:
...
def show
#reset_path = "foo_reset_path" # simply the string you'd use in the
# Rails code for opening the path
...
end
...
def reset
... # reset some variables to their default values
redirect_to foo_path # causes the show method to be called, and the HTML
# page to be redisplayed
end
File app/views/foo/show.html.erb:
...
<input type="hidden" id="reset_path" name="reset_path" value="<%= #reset_path %>">
...
<script>
$(document).ready(function() {
...
/* Hang functionality on the "Reset form" button. */
$('#reset_button').click(function () {
var reset_path = $('#reset_path').val();
window.open(reset_path, "_self")
});
...
})
</script>
I'm using JQuery here, but the basic idea should be clear. The script adds a hook to the button element whose id is reset_button, so that clicking on the button causes the reset method of foo_controller to be called.
What I did based on Teemu's great answer:
In your controller:
def show
#section = Section.find(params[:id])
respond_to do |format|
format.html
format.json { render json: #section}
end
end
In your view:
<input type="hidden" id="section_path" data-path="<%= #section.id %>" name="section_path" value="foo">
In your js:
var id = $('#section_path').attr('data-path');
$.ajax({
url:'/sections/'+ id +'.json',
type:"GET",
success: function (data){
console.info(data);
},
error: function (xhr, status){
console.info(xhr.error);
}
});
If you are using a JS pipeline that supports import (ES6 + webpacker), you might want to check out js_from_routes, a code-generation library that works seamlessly with Rails reloader.
For each endpoint that you'd like to access from JS, it will generate a method that can help you build a URL or make a request.
resources :video_clips, only: [:update], export: true
By using it in combination with axios, these generated helpers can be convenient and easy to use:
import VideoClipsRequests from '#requests/VideoClipsRequests'
VideoClipsRequests.update({ data: video })
.then(onVideoUpdate)
Have in mind that you can adjust the generated code by providing a custom template, so it can adapt to any technology you are using, even plain jQuery.
Benefits:
No need to manually specify the URL, preventing mistakes and saving development time.
If an action is renamed or removed, the helper ceases to exist, which causes an error that is easier to detect than a 404.
See http://tore.darell.no/pages/javascript_routes:
JavascriptRoutes converts your Rails routes into JavaScript. You can then access (generate) them in the browser (or any other JS environment). It supports both normal and named routes, and creates helper functions for the latter.
Update: It looks as though someone has forked this if you prefer jQuery: https://github.com/ajnsit/javascript_routes
gem install the "angular_rails_templates"
Create a file called angular_rails_templates.rb in the config/initializers folder
copy following code in the file and restart server. (including "module CustomERBEngine" for it cannot be added to code block by 4 space)
module CustomERBEngine
class ERBTemplate < Tilt::ERBTemplate
def evaluate(scope, locals, &block)
scope.class_eval do
include Rails.application.routes.url_helpers
include Rails.application.routes.mounted_helpers
include ActionView::Helpers
end
super
end
end
end
Tilt.register CustomERBEngine::ERBTemplate, '.erb'