I have a Rails project with Backbone.js and HAML as client side templating language.
in file app/assets/views/meeting.coffee:
class window.MeetingIndex extends Backbone.View
template: JST['meeting/index']
render: ->
#collection.fetch()
#$el.html(#template(collection: #collection))
this
in file app/assets/javascripts/templates/meeting/index.hamlc
- console.log(#collection.length) # prints 0 in console
- console.log(#collection.models) # prints [] in console
- console.log(#collection.at(0)) # prints undefined in console
- window.x = #collection
if I go to the browser console I get:
x.length # returns 2
x.models # returns [Meeting, Meeting]
x.at(0) # returns Meeting object
If I can access #collection variable in .hamlc file, because I am assigning it to window.x. Why can't I access the #collection items from the .hamlc file?
I need something like
- for model in #collection.models
%p= model.get('landlord_id')
%p= model.get('tenant_id')
%p= model.get('at')
to work
The Collection#fetch method is asynchronous (i.e. it is an AJAX call behind the curtains) so #collection.fetch() hasn't gotten anything back from the server when you try to use it in your view. However:
The options hash takes success and error callbacks which will be passed (collection, response) as arguments. When the model data returns from the server, the collection will reset.
So you can use the callbacks:
render: ->
#collection.fetch(
success: (collection, response) =>
#$el.html(#template(collection: #collection))
#
Or you can bind the view's render to the collection's reset event:
class window.MeetingIndex extends Backbone.View
template: JST['meeting/index']
initialize: ->
#collection.on('reset', #render)
#collection.fetch()
render: =>
#$el.html(#template(collection: #collection))
#
Then the fetch call in the view's initialize would indirectly trigger the proper render call when it gets something back from the server. This approach works best if your template knows what to do with an empty collection, perhaps it could detect an empty collection and display a "loading" message or just say "nothing's here yet".
Related
This is the location controller file that is going to access by the html code.
export default class extends Controller {
static targets = [ "visible", "map" ]
mapTargetConnected(element) {
this.name = "aaa"
}
add(event) {
console.log(this.name) // this line is logged that variable is undefined.
}
}
here is the HTML code
<%= form_with(model: #location, local: false, url: location_path(), data: {controller: 'location', action: 'ajax:beforeSend->location#add'}) do |form| %>
....
<% end %>
This is the code regarding form submit via ajax request. if i access the this.name variable inside the add method or click event its says the variable is undefined… but if i same name variable assign it in connect() method than it’s working…
but i want to assign variable at targetConnected method and use it in the add action method.Please suggest any solution or let me know if i'm doing wrong.
Most likely the add event is being triggered before the mapTargetConnected has run.
Stimulus will go through the DOM and match elements and their targets and then trigger the relevant someTargetConnected and connect lifecycle methods once the controller is set up.
However, this is not instant and there may be some nuance to how the timing works when you are working with other events.
You will need to work out when the actual map target is being added to the DOM and possibly do some logging to check that timing compared to when the ajax:beforeSend event triggers.
Sometimes, adding a setTimeout can assist as it will ensure that the code provided to it runs 'last' (there is some nuance to this, technically it is the next event cycle).
For example
add(event) {
// here the mapTargetConnected may not have run
setTimeout(() => {
// by this point, mapTargetConnected has hopefully now run
console.log(this.name);
});
}
It is hard to offer more help without a bit more specifics on what ajax:beforeSend is and when it triggers, along with what actually adds the map target to the DOM. It may be more helpful to write this question with the initially rendered HTML output (with the minimum parts to help guide the question).
In general, it is good to remember that in the browser, things do not happen instantly, while they may be fast there can be timing issues to be aware of.
weatherData;
getDataFromApi(formData) {
this.apiService.getWeather(formData.location).subscribe(data => this.weatherData = data)
console.log(this.weatherData)
}
This is the function to get data and then store it in a local variable weatherData, a JSON file is returned from the API.
To get data in the veiw(HTML) I'm using
<p class="item1">{{ this.weatherData?.request.query }}</p>.
It works fine here but when I need to use the WeatherData for another function then it is showing that the parameters passed is undefined.
The reason is that your code will work asynchronously and the console.log() will be executed before the API call is completed.
The reason that the data is displayed in view is that you subscribed to the data and it will be streamed to the view asynchronously. The view will be updated only after the API call is complete because of subscription. So you can see the data in the view and not in the console.
Try this code and it will work fine.
ngOnInit() {
// getting data for Delhi location
this.apiService.getWeather("Delhi").subscribe(data => {
this.weatherData = data;
console.log(this.weatherData);
});
}
The reason behind undefined was code works asynchronously. While you send the request compiler move to the next line which was console.log(this.weatherData). It print the value of weather data which was undefined when declaring the variable. When response arrive compiler than assign data with this.weatherData.
I am looking to add a global variable in smarty.
I added css styles with {$urls.css_url} in stylesheep.tpl
<link rel="stylesheet" type="text/css" href="{$urls.css_url}my.css">
It works very well, except that if I put the shop on debug mode, I have this error:
ContextErrorException in smarty_internal_templatebase.php(157) : eval()'d code line 393: Notice: Undefined index: css_url
What does that mean? that this variable will not be available in smarty?, so if I put the cache, it will not be loaded?
How to make variable {$ urls.css_url} available with smarty? everywhere on the site?
Which code should I put and where to put it so that the variable (url_css) remains available in debug mode?
Thanks for your help
Thank you for your help, you have a high level compared to me.
In fact the variable is already defined and is available everywhere.
In frontcontroler.php, I had this:
$assign_array = array(
'img_ps_url' => _PS_IMG_,
'img_cat_url' => _THEME_CAT_DIR_,
'img_lang_url' => _THEME_LANG_DIR_,
'img_prod_url' => _THEME_PROD_DIR_,
'img_manu_url' => _THEME_MANU_DIR_,
'img_sup_url' => _THEME_SUP_DIR_,
'img_ship_url' => _THEME_SHIP_DIR_,
'img_store_url' => _THEME_STORE_DIR_,
'img_col_url' => _THEME_COL_DIR_,
'img_url' => _THEME_IMG_DIR_,
'css_url' => _THEME_CSS_DIR_,
'js_url' => _THEME_JS_DIR_,
'pic_url' => _THEME_PROD_PIC_DIR_,
);
I then added the next line below to assign it in smarty.
$this->context->smarty->assign(array('urls' => $urls));
The variable is displayed, no problem but if I put the shop in debug mode:
/* Debug only */
if (!defined('_PS_MODE_DEV_')) {
define('_PS_MODE_DEV_', true);
}
I always have this:
ContextErrorException in smarty_internal_templatebase.php(157) : eval()'d code line 393: Notice: Undefined index: css_url
Does this indicate that there is no value? Why does its value disappear? (when I activate PS_MODE_DEV)
Thanks again.
{$urls.css_url} means to retrieve the the css_url value from the urls array.
Also the Notice you receive means the variable has no value, so it can't work at all, so maybe what you think is correct, but what you see comes from other variable / hook.
How to set a Smarty Variable
In case you want to set a smarty variable you will have first to assign it.
You can do it through a module, controller or a TPL.
From a module or a controller it will be available as soon as you declare it. To print or to debug it.
So, for example if you add it in the hookDisplayHeader or in actionFrontControllerSetMedia hooks the variable will available where you want to use it.
Also, to assign the value in a module or controller you will have to use a code like this:
$urls = array (
'css_url' => 'The URL to your CSS'
...
);
$this->context->smarty->assign(array('urls' => $urls));
Then you will be able to access it using {$urls.css_url}
How to know the already defined variables in Smarty
Enable the debug mode of your shop and then just add {debug} in any of your TPLs, this will show a Pop Up (remember to allow popups from your URL) with all the variables assigned to Smarty.
Maybe this is what you are looking for:
Version: Prestashop 1.7.2.4
We are going to do this overriding a class, in this case the following file: classes/controller/FrontController.php, this file assigns global variables for Prestashop.
Create a file: override/classes/controller/FrontController.php
Copy all the contents from: classes/controller/FrontController.php to our recently created file.
Check the following line: 1444, there is a function called getTemplateVarUrls(), inside this function there is already a variable css_url that points to theme css default dir : /public_html/themes/theme_name/assets/css
If you want to create a custom url variable write the code there, i.e:
public function getTemplateVarUrls()
{
$http = Tools::getCurrentUrlProtocolPrefix();
$base_url = $this->context->shop->getBaseURL(true, true);
//custom css url var points to a folder called "my_custom_css" in the root of the project
$customCssFolderUrl = $base_url.'/my_customs_css';
$urls = array(
'base_url' => $base_url,
'current_url' => $this->context->shop->getBaseURL(true, false).$_SERVER['REQUEST_URI'],
'shop_domain_url' => $this->context->shop->getBaseURL(true, false),
'custom_css_url' => $customCssFolderUrl ,
);
After we finish all this steps we proceed to delete public_html/app/cache/prod/class_index.php file, this to prevent Prestashop from ignoring our new file, to read more about this: http://doc.prestashop.com/display/PS16/Overriding+default+behaviors
Use your new variable: {$urls.custom_css_url} on any .tpl file
Hope this helps.
I'm brand new to Ember and I'm using Konacha to test my app. I'm having trouble using the data store in my tests. The following code attempts to check if the itemText property of an Item model is equal to the displayed text in the DOM:
it "should display the item text", ->
item = undefined
Ember.run ->
item = store.find('item', 1) # store is defined in the spec helper
content = item.get('itemText')
console.log(item) # Logs the correct item
console.log(content) # Logs undefined
$('.list-item:eq(0)').text().should.equal content # Fails since content is undefined
Clearly, the content = item.get('itemText') is not doing what I'm expecting it to. However, running the same code line by line in the console gives me back the property I want, so I'm not sure where I'm going wrong. I have a feeling I may be testing this in entirely the wrong way, so any feedback is appreciated.
I think your console logs is ran before the the model is fetched. What you need is a promise, have a look.
it "should display the item text", ->
item = undefined
Ember.run ->
item = store.find('item', 1).then (item) ->
content = item.get('itemText')
$('.list-item:eq(0)').text().should.equal content
I've spent a lot of time digging into sprockets' and tit's source code, trying to figure out how to pass variables / bindings to the Erb evaluation context. Here's what I'm trying to do: I need to serve a JS file whose contents change on a per-request basis. The portions that change depend on data stored in the DB, hence the need to route requests through the Rails app and the need to pass variables / bindings. On top of that the JS file uses the require directives to insert other JS files, hence the need to use sprockets.
Here's the code snippet that isn't working:
Controller file:
def ever_changing_js
#foobars = Foobar.all
MyApp::Application.assets.instance_eval do
def foobars
#foobars
end
end
render :text => MyApp::Application.assets.find_asset('ever_changing.js').to_s, :content_type => "application/javascript"
end
ever_changing.js:
//= require file1.js
//= require file2.js
// Some code that uses #foobars
How can I get this done? Any help would be appreciated.
JavaScript files should be completely static; Sprockets is not meant to do what you are trying to do.
Any data that changes on a per-request basis should be written to a <script> tag at the bottom of the template you are rendering.
app/assets/javascripts/user.js
(function(exports) {
function User(name) {
this.name = name;
}
User.prototype.speak() {
console.log(this.name + ' says, "Hello!"');
};
exports.User = User;
})(this);
app/views/users/show.html.erb
...
<%= javascript_include_tag('user') %>
<script>
(function() {
var user = new User(<%= #user.name %>);
$('#speak-button').click(function() {
user.speak();
});
})();
</script>
</html>
If you can give more context around your specific use case, I can give a more specific example.
I am trying to accomplish the same thing you are. I see a couple problems with your controller code snippet. Rather than doing an instance_eval on the Sprockets::Environment, you should class_eval the context_class, as shown in the Sprockets::Context documentation.
MyApp::Application.assets.context_class.class_eval do
def foobars
#foobars
end
end
Then foobars will be available to your ERb template.
As a sidenote, you can do
render js: MyApp::Application.assets.find_asset('ever_changing.js').to_s
instead of setting the content type yourself.