Admin metabox with custom post type dropdown option not update choosed input after saving

The issues with your code

  1. In the eca_meta_box_function() function, the selected option is not being selected because the option‘s value is not the post ID which is being used with the selected() function in WordPress: (wrapped for clarity)

    <option value="<?php echo $post->ID; ?>_<?php echo preg_replace('#[ -]+#', '-' ,$post->post_title ); ?>" <!-- wrapped -->
      <?php selected( $mv, $post->ID ); ?>><?php echo $post->post_title; ?></option>
    

    so that should be: (wrapped for clarity)

    <option value="<?php echo $post->ID; ?>" <!-- wrapped -->
      <?php selected( $mv, $post->ID ); ?>><?php echo $post->post_title; ?></option>
    
  2. In the save() function, you should capture two parameters (which WordPress passes to your function via the save_post hook) — 1) $post_id (the post ID); and 2) $post (the post data/object), like so:

    public function save( $post_id, $post )
    
  3. Also in the save() function, you already captured the submitted nonce (which you store in the $nonce variable), but you’re not using that variable:

    wp_verify_nonce( 'eca_nonce_check_value', 'eca_nonce_check' )
    

    and that prevents the selected option (or meta value) from being saved into the database! So change that to:

    wp_verify_nonce( $nonce, 'eca_nonce_check' )
    
  4. Also in the save() function, you used the wrong field name — the <select> in the eca_meta_box_function() function has its name set to eca-addons-course as in <select name="eca-addons-course"...>. And yet, in the save() function, you used:

    $_POST['ec-addons-course']
    

    when it should really be:

    $_POST['eca-addons-course']
    

    that mistake also prevents the selected option from being saved, obviously!

  5. Also in the save() function, I believe the meta key you should use is _ec-addons-course (which is used in the eca_meta_box_function() function) and not ec-addons-course:

    $mk = 'ec-addons-course';  // before; incorrect
    $mk = '_ec-addons-course'; // after; correct
    
  6. In the ec_addons_single_course_button_link() function, you’re not actually retrieving the saved meta data (and the $eca_course was not accessible from the function/context — you need to do global $eca_course; to get into that variable).

    So you can retrieve the saved meta data like so:

    $course_ID = get_post_meta( get_the_ID(), '_ec-addons-course', true );
    

    and use get_permalink() to retrieve the correct course URL address like so:

    $url = esc_url( get_permalink( $course_ID ) );
    

THE CORRECTED CODE

I didn’t re-indent the code (so that you could just compare it with yours, as in the current question). However, I renamed the $mv to $course_ID since that makes more meaningful..

class eca_metabox {

    public function __construct()
  {

        add_action( 'add_meta_boxes', array( $this, 'eca_add_meta_box' ) );
        add_action( 'save_post', array( $this, 'save' ), 10, 2 );

    }

    public function eca_add_meta_box()
  {

        add_meta_box(
      'eca-meta',
          'Scegli a quale corso deve linkare questo evento',
          array(
        $this,
        'eca_meta_box_function'
      ),
          'tribe_events',
          'normal',
          'high'
    );

    }

    public function eca_meta_box_function( $post )
  {

    wp_nonce_field( 'eca_nonce_check', 'eca_nonce_check_value' );
    $course_ID = get_post_meta( $post->ID, '_ec-addons-course', true );
    $post_type_object = get_post_type_object('course');
    $name = $post_type_object->name;
    $label = $post_type_object->label;
    $posts = get_posts(
      array(
        'post_type'=>           'course',
        'post_status'=>         'publish',
        'suppress_filters' =>   false,
        'posts_per_page'=>      -1,
      )
    ); ?>

    <select name="eca-addons-course" id="eca-addons-<?php echo $name; ?>">
      <option value = "" >Tutti i <?php echo strtolower( $label ); ?></option>
    <?php foreach ( $posts as $post ) { ?>
      <option value="<?php echo $post->ID; ?>" <?php selected( $course_ID, $post->ID ); ?>><?php echo $post->post_title; ?></option>
    <?php } ?>
    </select>

  <?php

  }

    public function save( $post_id, $post )
  {

        if( !isset($_POST['eca_nonce_check_value'] ) )
            return $post_id;

        $nonce = $_POST['eca_nonce_check_value'];
        if( !wp_verify_nonce( $nonce, 'eca_nonce_check' ) )
            return $post_id;

        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
            return $post_id;

    $post_type = get_post_type_object( $post->post_type );

        if (!current_user_can( $post_type->cap->edit_post, $post_id ))
        return $post_id;

    $new_meta_value = ( isset( $_POST['eca-addons-course'] ) ? sanitize_text_field( $_POST['eca-addons-course'] ) : '' );
    $mk = '_ec-addons-course';

    update_post_meta( $post->ID, $mk, $new_meta_value );
}

}

$eca_course = new eca_metabox();

add_action( 'tribe_events_single_event_after_the_content', 'ec_addons_single_course_button_link' );
function ec_addons_single_course_button_link()
{
  $course_ID = get_post_meta( get_the_ID(), '_ec-addons-course', true );
  $url = esc_url( get_permalink( $course_ID ) );

  $output = "<a id='courseLink' class="tribe-events-course-detail tribe-events-button" href="https://wordpress.stackexchange.com/questions/315172/$url" title="Vai al corso">Vai al dettaglio del corso </a>";

    echo '
        <script type="text/javascript">
            jQuery(document).ready(function($){
                var course = $("' . $output . '");
                $(".tribe-events-cal-links").append(course);
            });
        </script>
    ';
}