Re. C5-8.3: How to add js script for adding a block?

Permalink
I use:
public function on_page_view() {
        $html = $this->app->make('helper/html');
        $this->addHeaderItem($html->javascript('https://api-maps.yandex.ru/2.1/?lang=ru_RU'));
    }

to add the script in the header for the block. But when I just installed the package and want to add my block, the script doesn't run, I can't find it in the header. If I paste that into the add(), it still doesn't work.

How can I load it for adding the block for the first time?

Thank you.

linuxoid
 
JohntheFish replied on at Permalink Reply
JohntheFish
Usually better to use the core asset mechanism to register and then require an asset.
https://documentation.concrete5.org/developers/assets/registering-an...

For blocks, also look at the registerViewAssets() method for requiring assets (terminology is a bit confusing).
linuxoid replied on at Permalink Reply
linuxoid
I tried this:
public function on_start() {
        $this->set('app', $this->app);
        $al = \Concrete\Core\Asset\AssetList::getInstance();
        $al->register(
            'javascript', 
            'yandex-maps', 
            'https://api-maps.yandex.ru/2.1/?lang=ru_RU', 
            array(
                'position' => \Concrete\Core\Asset\Asset::ASSET_POSITION_HEADER,
                'local' => false
            )
        );
        $this->requireAsset('javascript', 'yandex-maps');
    }

but it doesn't work, still tells me the variable from the remote script is not defined.

I added $this->requireAsset('javascript', 'yandex-maps'); to the add() - no difference.
linuxoid replied on at Permalink Reply
linuxoid
I've checked the page source, that script doesn't get added to the header
pvernaglia replied on at Permalink Reply
pvernaglia
The script is on another server? I don't think you can register a remote script, I think it needs to be on your server. You might need to do something like:

$this->addHeaderItem('<script type="text/javascript" src="https://api-maps.yandex.ru/2.1/?lang=ru_RU"></script>');


But I might not be right about that, I usually put the script in my package directory and not use remote scripts
linuxoid replied on at Permalink Reply
linuxoid
Yes, it's on the remote server.

I've already tried that, it doesn't work either. That works for view, but that doesn't work for add.

The thing is if I go to that address, Firefox asks me to save a json.txt, it's not a .js file. I don't know how it works.
linuxoid replied on at Permalink Reply
linuxoid
if a remote script can't be registered, how can I load it in the add block form? Having a <script> tag with that source doesn't work.
pvernaglia replied on at Permalink Reply
pvernaglia
Some of my older blocks have 'CONTROLLER' included in the addHeaderItem,I don't remember the significance of that, but give it a try.

Did you try putting the addHeaderItem in the controller add() function? It's just a guess but I would give that a try too.

$this->addHeaderItem('<script type="text/javascript" src="https://api-maps.yandex.ru/2.1/?lang=ru_RU"></script>','CONTROLLER');
linuxoid replied on at Permalink Reply
linuxoid
Yep, tried both, doesn't show up in the header.

Also tried auto.js with:
(function () {
    $('body').append('<script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU" type="text/javascript"');
});
linuxoid replied on at Permalink Reply
linuxoid
Why doesn't including
<script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU" type="text/javascript"></script>

in the form.php work either? Shouldn't the script load in any case?
mnakalay replied on at Permalink Reply
mnakalay
it looks like there might be a problem with the script itslef and/or its host. Do you get any other error message in the console?
mnakalay replied on at Permalink Reply
mnakalay
I tried both your first and second solution
$this->addHeaderItem($html->javascript('https://api-maps.yandex.ru/2.1/?lang=ru_RU'));

and
$al->register(
            'javascript', 
            'yandex-maps', 
            'https://api-maps.yandex.ru/2.1/?lang=ru_RU', 
            array(
                'position' => Asset::ASSET_POSITION_HEADER,
                'local' => false
            )
        );
        $this->requireAsset('javascript', 'yandex-maps');

And they both worked.
You might have other problems in your code
linuxoid replied on at Permalink Reply
linuxoid
They do work perfectly well anywhere BUT during adding the block. The script loads a class 'ymaps' and the console tells me the class name is not found. But this only happens during adding the block for the first time. When the block is added (trying twice to add it, ignoring errors) or in the view.php - everything works fine.

I can't figure out how to make the script load during the add.
mnakalay replied on at Permalink Reply
mnakalay
Care to share your code?
linuxoid replied on at Permalink Reply
linuxoid
@mnakalay, I've sent you a PM with my package
mnakalay replied on at Permalink Reply
mnakalay
Yes I saw that and the problem is weird. I don't understand why C5 doesn't add the script to the header unless you do it in edit or add function. I'm still thinking about it.
linuxoid replied on at Permalink Reply
linuxoid
It adds the script in edit but NOT in add - that's the problem
mnakalay replied on at Permalink Reply
mnakalay
This is what I did and it seems to work.
First, remove all the code you have that tries to load the script. You're not going to use it. And that means in the controller and in the form.php. All of it.
You're going to load the script through JS and then listen to loading event to trigger the call.

In form.php, at the beginning of your JS, add this
loadScript('https://api-maps.yandex.ru/2.1/?lang=ru_RU', function(){
    ymaps.ready(init)
});
function loadScript(url, callback){
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.setAttribute('src', url);
    script.onreadystatechange = callback;
    script.onload = callback;
    var head = document.getElementsByTagName('head')[0];
    head.appendChild(script, head);
}

When you add your block, it will take a few seconds for the map to appear so you migh want to implement a spinner or a "please wait" message or something.
JohntheFish replied on at Permalink Reply
JohntheFish
There is a core js method ccm_addHeaderItem for loading a script (or css) from js.

Does pretty much the same as above (not as sophisticated as jQuery script loader);
linuxoid replied on at Permalink Reply
linuxoid
@mnakalay, I've removed all script loading code from everywhere and added your code to the form.php. Now the add block form pops up, map controls load but the map itself doesn't, and on hovering it multiplies hundreds of js errors.

I've also tried and added this to the form.php instead:
<script type="text/javascript">    
ccm_addHeaderItem("https://api-maps.yandex.ru/2.1/?lang=ru_RU", "JAVASCRIPT");</script>

and I still have the same error as before - the script doesn't load
JohntheFish replied on at Permalink Reply
JohntheFish
I use script assets in add/edit dialogs in many places with no issues between add and edit.

I don't have time to heIp directly at the moment. For now, a wild speculation - could it be browser security on same-source for scripts? See what happens if you use the same code to load a script from the site rather than a cdn.
linuxoid replied on at Permalink Reply
linuxoid
As I mentioned before, the script and whole map load fine in the edit and view. But that's only after the block is added. The script doesn't load nor does the map during the add.

So, basically if I try to add the block, the form doesn't even pop up and I see a js error in the console saying the 'ymaps' is unknown. If I ignore this and add the block again, this time the form pops up but the map is empty (doesn't load obviously, same js error), but I press to save, reload the page and now the map is displayed and if I go to edit the block everything works just fine.

So the issue is only with ADDING the block.
mnakalay replied on at Permalink Reply
mnakalay
The map seemed to load on block add using my solution. Did that fail for you too?
linuxoid replied on at Permalink Reply
linuxoid
Yes, that fails to load the map. It loads the form controls but not the map.
linuxoid replied on at Permalink Reply
linuxoid
I've cleared the form and only left these:
<?php     defined('C5_EXECUTE') or die("Access Denied.");
?>
<style>
#yandex_map {
    height: 300px;
    width: auto;
}
</style>
<fieldset>
    <div class="col-xs-12">
        <div class="form-group">
            <div id="block_note" class="alert alert-info" role="alert">
            <?php echo t('Click on map to set location'); ?>
            </div>             
            <div id="yandex_map"></div>

That opens the form but doesn't load the map.
mnakalay replied on at Permalink Reply
mnakalay
Well, I don't know what to say, it works for me, on block add.

The only thing I had to modify was to give latitude and longitude default values or else the map would appear but would throw an error because the center was empty.

I'm sending you the package I modified by PM.
linuxoid replied on at Permalink Reply 1 Attachment
linuxoid
Well, I'm puzzled then. I've just replaced my form with yours and all I got is just a gray rectangle (see attached pic) with hundreds of js errors in the console if I hover over it
mnakalay replied on at Permalink Reply
mnakalay
I just sent you a video showing you it works on my computer so there's some kind of wizardry at play here...
mnakalay replied on at Permalink Reply
mnakalay
And what you are showing in that screenshot is what I first got before I gave $latitude and $longitude default values (check at the top of form.php what I added)
linuxoid replied on at Permalink Reply
linuxoid
Oh, geeeeez, I've copied all but the first php bit. Now it works!!!

And I've just realized I forgot to set those 2 values in the add().

Thank you very very much for your help! It was driving me nuts.

I guess I can submit my package now )))
mnakalay replied on at Permalink Reply
mnakalay
that's the paradox of the PRB. If you had asked this over there we would have said "It is up to you to solve this problem and make it work, we're not here to fix your code for you"
But then in the forum, you get help from the same people... :-)

Naaahhh! I'm joking, I would have helped in the PRB as well because it was an interesting problem that I was curious to fix.

Having said so I strongly suggest you look a little more at your code and clean it up and make sure all your defaults are set and everything is peachy before submitting.